library(coda)
library(bayesplot) 
library(ggplot2)
library(ggsci)
library(khroma)
library(tidyverse)
library(reshape2)
library(yardstick) # for quick rmse
library(here)
knitr::opts_chunk$set(echo = TRUE, dpi = 300 )

Set up MCSim file

# this markdown file must be saved in top level directory for the following to work; the mcsim code depends on getwd results.
mdir <- "MCSim"
source(here::here(mdir,"setup_MCSim.R"))
# Make mod.exe (used to create mcsim executable from model file)
makemod() 
The mod.exe had been created.

Set filenames and load data

Set up dataset

id_lut <- multicheck$df_check %>% select(Level) %>% unique ()  %>%
  mutate(dataset = c( 
    rep("Decatur M Train", 9),
    rep("Decatur F Train", 9),
    rep("Decatur M Test", 9),
    rep("Decatur F Test", 10),
    'Paulsboro-Train','Horsham-Train',
    'Warminster-Test','Warrington-Train'), 
    Sex = c( 
    rep("M", 9),
    rep("F", 9),
    rep("M", 9),
    rep("F", 10),
    'Mixed', 'Mixed',  'Mixed', 'Mixed'),
    City = c( 
    rep("Decatur", 18),
    rep("Decatur", 19),
    'Paulsboro','Horsham','Warminster','Warrington'), 
    Train_Test = c( 
    rep("Train", 9),
    rep("Train", 9),
    rep("Test", 9),
    rep("Test", 10),
    'Train', 'Train', 'Test', 'Test'),
    datatype = c(
      rep("Individual",9+9+9+10),
      rep("Summary",4)),
    Simulation = row_number(),
    variable = paste0(dataset, " ",Simulation))

id_lut$dataset <- factor(id_lut$dataset,levels=
                           c("Decatur M Train","Decatur F Train","Arnsberg M Train",
                             "Arnsberg F Train","Decatur M Test","Decatur F Test","Arnsberg M Test",
                             "Arnsberg F Test","Minnesota Train","Minnesota Test",
                             'Lubeck-Bartell-Train', 'Lubeck-Bartell-Test',
                             'Little Hocking-Bartell-Train', 'Little Hocking-Bartell-Test',
                             'Little Hocking-Emmett-Test','Paulsboro-Train','Horsham-Train',
                             'Warminster-Test','Warrington-Train'))
id_lut$City <- factor(id_lut$City,levels = 
                        c("Decatur","Arnsberg","Minnesota",'Lubeck-Bartell',
                          'Little Hocking-Bartell','Little Hocking-Emmett',
                          'Paulsboro','Horsham','Warminster','Warrington'))
 

indiv_lut <- id_lut %>% 
  filter(City %in% c("Decatur")) %>%
  mutate(  dataset = as.factor(dataset))

nv <- data.frame(dataset =unique(indiv_lut$dataset), 
           variable= rep("Pop GM", 4),
           type= rep("Pop GM", 4), stringsAsFactors = FALSE)

Individual parameters

set.seed(314159)

indiv_parms <- indiv_lut
lnkparmnames <- paste("ln_k.",gsub("_",".",indiv_parms$Level),".",sep="")
lnVdparmnames <- paste("ln_Vd.",gsub("_",".",indiv_parms$Level),".",sep="")

parmsamp <- apply(multicheck$parms.samp,2,sample,1)

## Random z-score estimate of each parameter
indiv_parms$ln_k.z.samp <- parmsamp[lnkparmnames]
indiv_parms$ln_Vd.z.samp <- parmsamp[lnVdparmnames]

normd <- data.frame(x=qnorm(ppoints(200)))
normd$y <- dnorm(normd$x)

iplotk<-
  ggplot(subset(indiv_parms,Train_Test=="Train"))+
    geom_histogram(aes(x=ln_k.z.samp,after_stat(density)),bins=10)+facet_wrap(~City,ncol=1)+
    geom_line(aes(x=x,y=y),data=normd)+
    xlab("Individual z-scores for k") + theme_bw()

iplotVd<-
  ggplot(subset(indiv_parms,Train_Test=="Train"))+
    geom_histogram(aes(x=ln_Vd.z.samp,after_stat(density)),bins=10)+facet_wrap(~City,ncol=1)+
    geom_line(aes(x=x,y=y),data=normd)+
    xlab("Individual z-scores for Vd") + theme_bw()

print(iplotk)

print(iplotVd)

ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_k_PFHxS.pdf")),iplotk,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_k_PFHxS.png")),iplotk,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_Vd_PFHxS.pdf")),iplotVd,dpi=600)
Saving 3.5 x 3.5 in image
ggsave(file.path("output-plots",
             paste0( sa,"Indiv_zscores_Vd_PFHxS.png")),iplotVd,dpi=600)
Saving 3.5 x 3.5 in image

Scatter plot of predictions (median of multicheck samples) versus data.

This is a Figure 2 panel. Needed to use “scale=1.1” in ggsave to match PFOA.

nrow(multicheck$df_check)
[1] 39000
nrow(id_lut)
[1] 41
multicheck$df_check %>% left_join(id_lut) %>% nrow()
Joining, by = c("Level", "Simulation")
[1] 39000
names(multicheck$df_check)
[1] "Level"      "Simulation" "Output_Var" "Time"       "Data"      
[6] "Prediction"
Level

Simulation

Output_Var

Time

Data

Prediction
multicheck2 <- multicheck$df_check %>% 
  left_join(id_lut, by = c("Level", "Simulation"))%>% 
  group_by_at ( vars(-Prediction)) %>% 
  summarise(Prediction = median(Prediction)) %>%
  ungroup() %>%
  group_by(City) %>% 
  mutate(Train_Test = factor(Train_Test, levels = c("Train", "Test")),
         `City (datatype)` = factor (paste0("\n", City, "\n(", datatype, ")\n") ),
         label = case_when(Train_Test=="Train" ~ "G: PFHxS Train",
                           Train_Test=="Test"  ~ "H: PFHxS Test",
                           TRUE ~ ""))
`summarise()` has grouped output by 'Level', 'Simulation', 'Output_Var', 'Time', 'Data', 'dataset', 'Sex', 'City', 'Train_Test', 'datatype'. You can override using the `.groups` argument.
#define color for testing boxplots
bp_cols <- c (as.character (khroma::colour("muted")(9)) , "#191919")   
bp_cols <-bp_cols[c(1,7,10:8)]# plot_scheme_colourblind(bp_cols) 

### Create aesthetics lookup
aes_lut <- multicheck2 %>% ungroup() %>% 
  group_by(City, datatype,  `City (datatype)` ) %>% summarise () %>% ungroup() %>%
  mutate( cols = bp_cols, city_fills =   bp_cols , 
          # for individual level on point plot (multicheck2), darken outlines for visibility, use standard colors otherwise
         city_outlines =  if_else(datatype == "Individual"  ,  colorspace::darken(city_fills, 0.3), city_fills) ,  
         shapes = case_when(datatype == "Individual"  & `City` %in% c('Decatur', 'Arnsberg', 'Minnesota')   ~  23,
                            datatype == "Summary" &`City` %in% c("Horsham", "Warminster",  "Warrington") ~ 2,
                            datatype == "Summary" & `City` == "Paulsboro" ~ 1,
                            TRUE ~ 18                                ), 
         size = if_else(datatype =="Individual", 1.75, 2.5 ) )  
`summarise()` has grouped output by 'City', 'datatype'. You can override using the `.groups` argument.
source( paste0(gsub(basename(here()), 'shared_functions', here()), '/plot_scatter_mcheck.r'))

p2 <- plot_scatter_mcheck(dframe = multicheck2,  pfas_nom = pfas_name, aes_lut_fn = aes_lut )
Joining, by = "facet_label"
print(p2) 

ggsave(here ("output-plots", paste0( sa,"multicheckplot_", pfas_name,
               ".pdf")),p2,dpi=600, scale=1.1)
Saving 8.8 x 3.85 in image
ggsave(here ("output-plots", paste0( sa,"multicheckplot_", pfas_name,
               ".png")),p2,dpi=600, scale=1.1)
Saving 8.8 x 3.85 in image
multicheck2$PFAS <- "PFHxS"
multiplot_scatter_dat <- list(aes_lut = aes_lut, multicheck2 = multicheck2) # save out for use in commbined plot
save(multiplot_scatter_dat, file =  "pfhxs_multiplot_scatter.Rdata")

Parse multicheck

df_check <- multicheck$df_check
df_check <- subset(df_check,Data > 0) 

n1 <- nrow(df_check)
id_chks <- df_check %>% select(Level) %>% unique() %>% bind_cols(id_lut)  %>%
  mutate(dataset = as.factor(dataset), Sex = as.factor(Sex), City = as.factor(City), 
         Train_Test = as.factor(Train_Test))
New names:
* Level -> Level...1
* Level -> Level...2
df_check <- df_check %>% left_join(id_chks)%>%
  mutate(Dataset = paste(as.character(dataset), Simulation),
         Sex = ordered(Sex, levels = c("M", "F", "Mixed"), 
                       labels = c("Male", "Female", "Mixed (all sexes)")))
Joining, by = "Simulation"
n2 <- nrow(df_check)
if(n1 != n2)print("duplicates created in id-lut join")
df_check$Time.desc <- as.character(paste0("T=",df_check$Time))
df_check$Time.desc[df_check$Time.desc == "T=1e-06"] <- "SteadyState"
df_check$Dataset.Time <- interaction(df_check$Dataset,
                                     df_check$Time.desc,lex.order=TRUE)
df_check$Dataset.Time <- factor(df_check$Dataset.Time,
                                levels=levels(df_check$Dataset.Time))
calibdata <- df_check[,names(df_check) != "Prediction"]
calibdata <- calibdata[!duplicated(calibdata),]
print(calibdata)
        Level Simulation Output_Var  Time   Data  Level...1  Level...2
1   1_1_1_1_1          1     Cserum 0.000 15.400  1_1_1_1_1  1_1_1_1_1
2   1_1_1_1_1          1     Cserum 5.802 16.600  1_1_1_1_1  1_1_1_1_1
3   1_1_1_1_2          2     Cserum 0.000  4.900  1_1_1_1_2  1_1_1_1_2
4   1_1_1_1_2          2     Cserum 5.802  6.100  1_1_1_1_2  1_1_1_1_2
5   1_1_1_1_3          3     Cserum 0.000 11.300  1_1_1_1_3  1_1_1_1_3
6   1_1_1_1_3          3     Cserum 5.802  7.800  1_1_1_1_3  1_1_1_1_3
7   1_1_1_1_4          4     Cserum 0.000 12.800  1_1_1_1_4  1_1_1_1_4
8   1_1_1_1_4          4     Cserum 5.802  5.600  1_1_1_1_4  1_1_1_1_4
9   1_1_1_1_5          5     Cserum 0.000 20.900  1_1_1_1_5  1_1_1_1_5
10  1_1_1_1_5          5     Cserum 5.802 12.400  1_1_1_1_5  1_1_1_1_5
11  1_1_1_1_6          6     Cserum 0.000  6.300  1_1_1_1_6  1_1_1_1_6
12  1_1_1_1_6          6     Cserum 5.802  6.700  1_1_1_1_6  1_1_1_1_6
13  1_1_1_1_7          7     Cserum 0.000 24.400  1_1_1_1_7  1_1_1_1_7
14  1_1_1_1_7          7     Cserum 5.802 18.100  1_1_1_1_7  1_1_1_1_7
15  1_1_1_1_8          8     Cserum 0.000 24.200  1_1_1_1_8  1_1_1_1_8
16  1_1_1_1_8          8     Cserum 5.802 20.200  1_1_1_1_8  1_1_1_1_8
17  1_1_1_1_9          9     Cserum 0.000  7.800  1_1_1_1_9  1_1_1_1_9
18  1_1_1_1_9          9     Cserum 5.802  8.500  1_1_1_1_9  1_1_1_1_9
19 1_1_1_1_10         10     Cserum 0.000  2.300 1_1_1_1_10 1_1_1_1_10
20 1_1_1_1_10         10     Cserum 5.802  2.500 1_1_1_1_10 1_1_1_1_10
21 1_1_1_1_11         11     Cserum 0.000 12.900 1_1_1_1_11 1_1_1_1_11
22 1_1_1_1_11         11     Cserum 5.802 13.700 1_1_1_1_11 1_1_1_1_11
23 1_1_1_1_12         12     Cserum 0.000  2.400 1_1_1_1_12 1_1_1_1_12
24 1_1_1_1_12         12     Cserum 5.802  3.300 1_1_1_1_12 1_1_1_1_12
25 1_1_1_1_13         13     Cserum 0.000  2.700 1_1_1_1_13 1_1_1_1_13
26 1_1_1_1_13         13     Cserum 5.802  4.000 1_1_1_1_13 1_1_1_1_13
27 1_1_1_1_14         14     Cserum 0.000 18.300 1_1_1_1_14 1_1_1_1_14
28 1_1_1_1_14         14     Cserum 5.802 18.400 1_1_1_1_14 1_1_1_1_14
29 1_1_1_1_15         15     Cserum 0.000 12.900 1_1_1_1_15 1_1_1_1_15
30 1_1_1_1_15         15     Cserum 5.802 13.200 1_1_1_1_15 1_1_1_1_15
31 1_1_1_1_16         16     Cserum 0.000  3.300 1_1_1_1_16 1_1_1_1_16
32 1_1_1_1_16         16     Cserum 5.802  4.100 1_1_1_1_16 1_1_1_1_16
33 1_1_1_1_17         17     Cserum 0.000 16.900 1_1_1_1_17 1_1_1_1_17
34 1_1_1_1_17         17     Cserum 5.802 12.300 1_1_1_1_17 1_1_1_1_17
35 1_1_1_1_18         18     Cserum 0.000  8.700 1_1_1_1_18 1_1_1_1_18
36 1_1_1_1_18         18     Cserum 5.802  6.500 1_1_1_1_18 1_1_1_1_18
37  1_1_1_2_1         19     Cserum 0.000  6.300  1_1_1_2_1  1_1_1_2_1
38  1_1_1_2_1         19     Cserum 5.802  4.600  1_1_1_2_1  1_1_1_2_1
39  1_1_1_2_2         20     Cserum 0.000  7.100  1_1_1_2_2  1_1_1_2_2
40  1_1_1_2_2         20     Cserum 5.802  7.400  1_1_1_2_2  1_1_1_2_2
41  1_1_1_2_3         21     Cserum 0.000 19.500  1_1_1_2_3  1_1_1_2_3
42  1_1_1_2_3         21     Cserum 5.802 14.000  1_1_1_2_3  1_1_1_2_3
43  1_1_1_2_4         22     Cserum 0.000  7.500  1_1_1_2_4  1_1_1_2_4
44  1_1_1_2_4         22     Cserum 5.802  9.000  1_1_1_2_4  1_1_1_2_4
45  1_1_1_2_5         23     Cserum 0.000  8.600  1_1_1_2_5  1_1_1_2_5
46  1_1_1_2_5         23     Cserum 5.802  9.200  1_1_1_2_5  1_1_1_2_5
47  1_1_1_2_6         24     Cserum 0.000 12.400  1_1_1_2_6  1_1_1_2_6
48  1_1_1_2_6         24     Cserum 5.802 12.800  1_1_1_2_6  1_1_1_2_6
49  1_1_1_2_7         25     Cserum 0.000  8.900  1_1_1_2_7  1_1_1_2_7
50  1_1_1_2_7         25     Cserum 5.802  6.600  1_1_1_2_7  1_1_1_2_7
51  1_1_1_2_8         26     Cserum 0.000  7.400  1_1_1_2_8  1_1_1_2_8
52  1_1_1_2_8         26     Cserum 5.802  6.300  1_1_1_2_8  1_1_1_2_8
53  1_1_1_2_9         27     Cserum 0.000 14.300  1_1_1_2_9  1_1_1_2_9
54  1_1_1_2_9         27     Cserum 5.802 15.800  1_1_1_2_9  1_1_1_2_9
55 1_1_1_2_10         28     Cserum 0.000  3.800 1_1_1_2_10 1_1_1_2_10
56 1_1_1_2_10         28     Cserum 5.802  4.200 1_1_1_2_10 1_1_1_2_10
57 1_1_1_2_11         29     Cserum 0.000 22.100 1_1_1_2_11 1_1_1_2_11
58 1_1_1_2_11         29     Cserum 5.802 26.000 1_1_1_2_11 1_1_1_2_11
59 1_1_1_2_12         30     Cserum 0.000  6.500 1_1_1_2_12 1_1_1_2_12
60 1_1_1_2_12         30     Cserum 5.802  5.800 1_1_1_2_12 1_1_1_2_12
61 1_1_1_2_13         31     Cserum 0.000  7.500 1_1_1_2_13 1_1_1_2_13
62 1_1_1_2_13         31     Cserum 5.802  7.900 1_1_1_2_13 1_1_1_2_13
63 1_1_1_2_14         32     Cserum 0.000  7.500 1_1_1_2_14 1_1_1_2_14
64 1_1_1_2_14         32     Cserum 5.802  6.800 1_1_1_2_14 1_1_1_2_14
65 1_1_1_2_15         33     Cserum 0.000  7.500 1_1_1_2_15 1_1_1_2_15
66 1_1_1_2_15         33     Cserum 5.802  2.400 1_1_1_2_15 1_1_1_2_15
67 1_1_1_2_16         34     Cserum 0.000  6.000 1_1_1_2_16 1_1_1_2_16
68 1_1_1_2_16         34     Cserum 5.802  6.800 1_1_1_2_16 1_1_1_2_16
69 1_1_1_2_17         35     Cserum 0.000 18.200 1_1_1_2_17 1_1_1_2_17
70 1_1_1_2_17         35     Cserum 5.802 13.200 1_1_1_2_17 1_1_1_2_17
71 1_1_1_2_18         36     Cserum 0.000  5.300 1_1_1_2_18 1_1_1_2_18
72 1_1_1_2_18         36     Cserum 5.802  3.900 1_1_1_2_18 1_1_1_2_18
73 1_1_1_2_19         37     Cserum 0.000  5.600 1_1_1_2_19 1_1_1_2_19
74 1_1_1_2_19         37     Cserum 5.802  5.400 1_1_1_2_19 1_1_1_2_19
75      1_2_1         38 M_Cbgd_Css 2.200  2.593      1_2_1      1_2_1
76      1_3_1         39 M_Cbgd_Css 2.000 27.340      1_3_1      1_3_1
77      1_4_1         40 M_Cbgd_Css 2.000 23.157      1_4_1      1_4_1
78    1_4_2_1         41 M_Cbgd_Css 2.000 14.851    1_4_2_1    1_4_2_1
            dataset               Sex       City Train_Test   datatype
1   Decatur M Train              Male    Decatur      Train Individual
2   Decatur M Train              Male    Decatur      Train Individual
3   Decatur M Train              Male    Decatur      Train Individual
4   Decatur M Train              Male    Decatur      Train Individual
5   Decatur M Train              Male    Decatur      Train Individual
6   Decatur M Train              Male    Decatur      Train Individual
7   Decatur M Train              Male    Decatur      Train Individual
8   Decatur M Train              Male    Decatur      Train Individual
9   Decatur M Train              Male    Decatur      Train Individual
10  Decatur M Train              Male    Decatur      Train Individual
11  Decatur M Train              Male    Decatur      Train Individual
12  Decatur M Train              Male    Decatur      Train Individual
13  Decatur M Train              Male    Decatur      Train Individual
14  Decatur M Train              Male    Decatur      Train Individual
15  Decatur M Train              Male    Decatur      Train Individual
16  Decatur M Train              Male    Decatur      Train Individual
17  Decatur M Train              Male    Decatur      Train Individual
18  Decatur M Train              Male    Decatur      Train Individual
19  Decatur F Train            Female    Decatur      Train Individual
20  Decatur F Train            Female    Decatur      Train Individual
21  Decatur F Train            Female    Decatur      Train Individual
22  Decatur F Train            Female    Decatur      Train Individual
23  Decatur F Train            Female    Decatur      Train Individual
24  Decatur F Train            Female    Decatur      Train Individual
25  Decatur F Train            Female    Decatur      Train Individual
26  Decatur F Train            Female    Decatur      Train Individual
27  Decatur F Train            Female    Decatur      Train Individual
28  Decatur F Train            Female    Decatur      Train Individual
29  Decatur F Train            Female    Decatur      Train Individual
30  Decatur F Train            Female    Decatur      Train Individual
31  Decatur F Train            Female    Decatur      Train Individual
32  Decatur F Train            Female    Decatur      Train Individual
33  Decatur F Train            Female    Decatur      Train Individual
34  Decatur F Train            Female    Decatur      Train Individual
35  Decatur F Train            Female    Decatur      Train Individual
36  Decatur F Train            Female    Decatur      Train Individual
37   Decatur M Test              Male    Decatur       Test Individual
38   Decatur M Test              Male    Decatur       Test Individual
39   Decatur M Test              Male    Decatur       Test Individual
40   Decatur M Test              Male    Decatur       Test Individual
41   Decatur M Test              Male    Decatur       Test Individual
42   Decatur M Test              Male    Decatur       Test Individual
43   Decatur M Test              Male    Decatur       Test Individual
44   Decatur M Test              Male    Decatur       Test Individual
45   Decatur M Test              Male    Decatur       Test Individual
46   Decatur M Test              Male    Decatur       Test Individual
47   Decatur M Test              Male    Decatur       Test Individual
48   Decatur M Test              Male    Decatur       Test Individual
49   Decatur M Test              Male    Decatur       Test Individual
50   Decatur M Test              Male    Decatur       Test Individual
51   Decatur M Test              Male    Decatur       Test Individual
52   Decatur M Test              Male    Decatur       Test Individual
53   Decatur M Test              Male    Decatur       Test Individual
54   Decatur M Test              Male    Decatur       Test Individual
55   Decatur F Test            Female    Decatur       Test Individual
56   Decatur F Test            Female    Decatur       Test Individual
57   Decatur F Test            Female    Decatur       Test Individual
58   Decatur F Test            Female    Decatur       Test Individual
59   Decatur F Test            Female    Decatur       Test Individual
60   Decatur F Test            Female    Decatur       Test Individual
61   Decatur F Test            Female    Decatur       Test Individual
62   Decatur F Test            Female    Decatur       Test Individual
63   Decatur F Test            Female    Decatur       Test Individual
64   Decatur F Test            Female    Decatur       Test Individual
65   Decatur F Test            Female    Decatur       Test Individual
66   Decatur F Test            Female    Decatur       Test Individual
67   Decatur F Test            Female    Decatur       Test Individual
68   Decatur F Test            Female    Decatur       Test Individual
69   Decatur F Test            Female    Decatur       Test Individual
70   Decatur F Test            Female    Decatur       Test Individual
71   Decatur F Test            Female    Decatur       Test Individual
72   Decatur F Test            Female    Decatur       Test Individual
73   Decatur F Test            Female    Decatur       Test Individual
74   Decatur F Test            Female    Decatur       Test Individual
75  Paulsboro-Train Mixed (all sexes)  Paulsboro      Train    Summary
76    Horsham-Train Mixed (all sexes)    Horsham      Train    Summary
77  Warminster-Test Mixed (all sexes) Warminster       Test    Summary
78 Warrington-Train Mixed (all sexes) Warrington       Test    Summary
              variable             Dataset Time.desc               Dataset.Time
1    Decatur M Train 1   Decatur M Train 1       T=0      Decatur M Train 1.T=0
2    Decatur M Train 1   Decatur M Train 1   T=5.802  Decatur M Train 1.T=5.802
3    Decatur M Train 2   Decatur M Train 2       T=0      Decatur M Train 2.T=0
4    Decatur M Train 2   Decatur M Train 2   T=5.802  Decatur M Train 2.T=5.802
5    Decatur M Train 3   Decatur M Train 3       T=0      Decatur M Train 3.T=0
6    Decatur M Train 3   Decatur M Train 3   T=5.802  Decatur M Train 3.T=5.802
7    Decatur M Train 4   Decatur M Train 4       T=0      Decatur M Train 4.T=0
8    Decatur M Train 4   Decatur M Train 4   T=5.802  Decatur M Train 4.T=5.802
9    Decatur M Train 5   Decatur M Train 5       T=0      Decatur M Train 5.T=0
10   Decatur M Train 5   Decatur M Train 5   T=5.802  Decatur M Train 5.T=5.802
11   Decatur M Train 6   Decatur M Train 6       T=0      Decatur M Train 6.T=0
12   Decatur M Train 6   Decatur M Train 6   T=5.802  Decatur M Train 6.T=5.802
13   Decatur M Train 7   Decatur M Train 7       T=0      Decatur M Train 7.T=0
14   Decatur M Train 7   Decatur M Train 7   T=5.802  Decatur M Train 7.T=5.802
15   Decatur M Train 8   Decatur M Train 8       T=0      Decatur M Train 8.T=0
16   Decatur M Train 8   Decatur M Train 8   T=5.802  Decatur M Train 8.T=5.802
17   Decatur M Train 9   Decatur M Train 9       T=0      Decatur M Train 9.T=0
18   Decatur M Train 9   Decatur M Train 9   T=5.802  Decatur M Train 9.T=5.802
19  Decatur F Train 10  Decatur F Train 10       T=0     Decatur F Train 10.T=0
20  Decatur F Train 10  Decatur F Train 10   T=5.802 Decatur F Train 10.T=5.802
21  Decatur F Train 11  Decatur F Train 11       T=0     Decatur F Train 11.T=0
22  Decatur F Train 11  Decatur F Train 11   T=5.802 Decatur F Train 11.T=5.802
23  Decatur F Train 12  Decatur F Train 12       T=0     Decatur F Train 12.T=0
24  Decatur F Train 12  Decatur F Train 12   T=5.802 Decatur F Train 12.T=5.802
25  Decatur F Train 13  Decatur F Train 13       T=0     Decatur F Train 13.T=0
26  Decatur F Train 13  Decatur F Train 13   T=5.802 Decatur F Train 13.T=5.802
27  Decatur F Train 14  Decatur F Train 14       T=0     Decatur F Train 14.T=0
28  Decatur F Train 14  Decatur F Train 14   T=5.802 Decatur F Train 14.T=5.802
29  Decatur F Train 15  Decatur F Train 15       T=0     Decatur F Train 15.T=0
30  Decatur F Train 15  Decatur F Train 15   T=5.802 Decatur F Train 15.T=5.802
31  Decatur F Train 16  Decatur F Train 16       T=0     Decatur F Train 16.T=0
32  Decatur F Train 16  Decatur F Train 16   T=5.802 Decatur F Train 16.T=5.802
33  Decatur F Train 17  Decatur F Train 17       T=0     Decatur F Train 17.T=0
34  Decatur F Train 17  Decatur F Train 17   T=5.802 Decatur F Train 17.T=5.802
35  Decatur F Train 18  Decatur F Train 18       T=0     Decatur F Train 18.T=0
36  Decatur F Train 18  Decatur F Train 18   T=5.802 Decatur F Train 18.T=5.802
37   Decatur M Test 19   Decatur M Test 19       T=0      Decatur M Test 19.T=0
38   Decatur M Test 19   Decatur M Test 19   T=5.802  Decatur M Test 19.T=5.802
39   Decatur M Test 20   Decatur M Test 20       T=0      Decatur M Test 20.T=0
40   Decatur M Test 20   Decatur M Test 20   T=5.802  Decatur M Test 20.T=5.802
41   Decatur M Test 21   Decatur M Test 21       T=0      Decatur M Test 21.T=0
42   Decatur M Test 21   Decatur M Test 21   T=5.802  Decatur M Test 21.T=5.802
43   Decatur M Test 22   Decatur M Test 22       T=0      Decatur M Test 22.T=0
44   Decatur M Test 22   Decatur M Test 22   T=5.802  Decatur M Test 22.T=5.802
45   Decatur M Test 23   Decatur M Test 23       T=0      Decatur M Test 23.T=0
46   Decatur M Test 23   Decatur M Test 23   T=5.802  Decatur M Test 23.T=5.802
47   Decatur M Test 24   Decatur M Test 24       T=0      Decatur M Test 24.T=0
48   Decatur M Test 24   Decatur M Test 24   T=5.802  Decatur M Test 24.T=5.802
49   Decatur M Test 25   Decatur M Test 25       T=0      Decatur M Test 25.T=0
50   Decatur M Test 25   Decatur M Test 25   T=5.802  Decatur M Test 25.T=5.802
51   Decatur M Test 26   Decatur M Test 26       T=0      Decatur M Test 26.T=0
52   Decatur M Test 26   Decatur M Test 26   T=5.802  Decatur M Test 26.T=5.802
53   Decatur M Test 27   Decatur M Test 27       T=0      Decatur M Test 27.T=0
54   Decatur M Test 27   Decatur M Test 27   T=5.802  Decatur M Test 27.T=5.802
55   Decatur F Test 28   Decatur F Test 28       T=0      Decatur F Test 28.T=0
56   Decatur F Test 28   Decatur F Test 28   T=5.802  Decatur F Test 28.T=5.802
57   Decatur F Test 29   Decatur F Test 29       T=0      Decatur F Test 29.T=0
58   Decatur F Test 29   Decatur F Test 29   T=5.802  Decatur F Test 29.T=5.802
59   Decatur F Test 30   Decatur F Test 30       T=0      Decatur F Test 30.T=0
60   Decatur F Test 30   Decatur F Test 30   T=5.802  Decatur F Test 30.T=5.802
61   Decatur F Test 31   Decatur F Test 31       T=0      Decatur F Test 31.T=0
62   Decatur F Test 31   Decatur F Test 31   T=5.802  Decatur F Test 31.T=5.802
63   Decatur F Test 32   Decatur F Test 32       T=0      Decatur F Test 32.T=0
64   Decatur F Test 32   Decatur F Test 32   T=5.802  Decatur F Test 32.T=5.802
65   Decatur F Test 33   Decatur F Test 33       T=0      Decatur F Test 33.T=0
66   Decatur F Test 33   Decatur F Test 33   T=5.802  Decatur F Test 33.T=5.802
67   Decatur F Test 34   Decatur F Test 34       T=0      Decatur F Test 34.T=0
68   Decatur F Test 34   Decatur F Test 34   T=5.802  Decatur F Test 34.T=5.802
69   Decatur F Test 35   Decatur F Test 35       T=0      Decatur F Test 35.T=0
70   Decatur F Test 35   Decatur F Test 35   T=5.802  Decatur F Test 35.T=5.802
71   Decatur F Test 36   Decatur F Test 36       T=0      Decatur F Test 36.T=0
72   Decatur F Test 36   Decatur F Test 36   T=5.802  Decatur F Test 36.T=5.802
73   Decatur F Test 37   Decatur F Test 37       T=0      Decatur F Test 37.T=0
74   Decatur F Test 37   Decatur F Test 37   T=5.802  Decatur F Test 37.T=5.802
75  Paulsboro-Train 38  Paulsboro-Train 38     T=2.2   Paulsboro-Train 38.T=2.2
76    Horsham-Train 39    Horsham-Train 39       T=2       Horsham-Train 39.T=2
77  Warminster-Test 40  Warminster-Test 40       T=2     Warminster-Test 40.T=2
78 Warrington-Train 41 Warrington-Train 41       T=2    Warrington-Train 41.T=2
#Multicheck plot

# Split Steady State Group into different populations for boxplot grouping
#df_check[df_check$Time.desc == "SteadyState" & grepl("Lubeck",df_check$Dataset),]$Time.desc <- "Lubeck"
#df_check[df_check$Time.desc == "SteadyState" & grepl("Little Hocking",df_check$Dataset),]$Time.desc <- "Little Hocking"

Modify aesthetics lookup table for boxplots

##  additional source aesthetic lookup table for grey-scale time (years);  merged legends save space on plotting output
times <- df_check%>% select(Time.desc, Time) %>%  unique () %>% 
  mutate(rank = rank(Time) , grey = grey.colors(start=1,end=0.4, n = n()),
         alpha = (rank)/8) %>% 
  select(-Time)
 
df_check <- df_check %>% mutate (legend_label = (paste0(City, "\n", Time.desc ) )) # add legend-labels
aes_lut <- df_check %>% 
  select(City, Train_Test, datatype,Time, Time.desc, legend_label) %>% unique () %>%
   left_join(aes_lut[, c("City", "cols")], by = "City") %>% ungroup () %>% unique ()%>%
   left_join (times, by = "Time.desc") %>% 
   arrange(datatype, City, Train_Test, Time)    %>% 
   mutate(alpha = if_else(City == "Horsham", alpha/2, alpha)) %>% # otherwise too dark with this color
  mutate_if(is.factor, as.character) 

Decatur boxplots

Changed grey start to 1 instead of 0.8, end at 0.6 instead of 0.4. Changed shape of symbols so they are filled.

#GH
# Decatur 

df_decat  <- df_check %>%   
  filter(City == "Decatur" & Train_Test %in% c ("Train", "Test")) %>% 
  mutate(panel = ordered (Train_Test, levels = c ("Train", "Test"), 
                          labels = c("G: PFHxS Decatur Train", "H: PFHxS Decatur Test") ))

aes_lut_df_df_decat <- aes_lut %>% 
  filter(City == "Decatur" & Train_Test %in% c ("Train", "Test")) %>% 
  mutate_if(is.factor, as.character) 

source( paste0(gsub(basename(here()), 'shared_functions', here()), '/plot_sum_boxplot.r'))


plt_train <- plot_sum_boxplot   (dframe = df_decat, aes_lut= aes_lut_df_df_decat, facets = TRUE , pfas_nom = pfas_name     ) 
print(plt_train)

ggsave(here ("output-plots",paste0( sa,"DecaturTrainTestboxplot",pfas_name,".pdf")),plt_train,dpi=600)
Saving 6.5 x 3.5 in image
ggsave(here ("output-plots",paste0( sa,"DecaturTrainTestboxplot",pfas_name,".png")),plt_train,dpi=600)
Saving 6.5 x 3.5 in image

All boxplots

Changed grey start to 1 instead of 0.8, end at 0.6 instead of 0.4. Added shapes and fills to data points.

lets <- LETTERS;
names(lets)[1:(length(unique(df_check$dataset))-4)]<-as.character(unique(df_check$dataset))[5:length(unique(df_check$dataset))]

for (d in unique(df_check$dataset)) { # d = unique(df_check$dataset)[11]
    ddset <- df_check %>%    
    filter(dataset == d) 
    
    aes_lut_ddset <- ddset %>% select(legend_label,  City,Train_Test,datatype, Time.desc  ) %>% unique () %>% inner_join(aes_lut)
      
    gt <- ifelse(is.na(lets[d]),d,paste0(lets[d],": ", d))
    plt <- plot_sum_boxplot(dframe = ddset, aes_lut= aes_lut_ddset, gtitle= gt, facets = FALSE, pfas_nom = pfas_name)
     
  print(plt)
  ggsave(here ("output-plots",
                paste0( sa, d,"-boxplot-", 
                pfas_name,".pdf")) ,
         plt,dpi=600)
  
    ggsave(here ("output-plots",
                paste0( sa, d,"-boxplot-", 
                pfas_name,".png")) ,
         plt,dpi=600)

}
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")
Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image
Joining, by = c("legend_label", "City", "Train_Test", "datatype", "Time.desc")

Saving 6.5 x 3.5 in image
Saving 6.5 x 3.5 in image

### make Training plot  

df_d_trt <- df_check %>%   
     filter( (Train_Test == "Train") & ((Output_Var == "M_Cbgd_Css") | (Output_Var == "M_Cserum"))) %>%
     mutate_if(is.factor, as.character) %>%  # drop factor levels unused
     mutate(Dataset.Time = factor(Dataset.Time)) 
 

 aes_lut_df_d_trt <-  df_d_trt %>% select(City, datatype,Time, Time.desc, legend_label) %>% 
   inner_join(aes_lut  ) %>% 
   select(-Train_Test) %>% ungroup () %>% unique ()  
Joining, by = c("City", "datatype", "Time", "Time.desc", "legend_label")
plt_train <-    plot_sum_boxplot(dframe = df_d_trt, aes_lut= aes_lut_df_d_trt,   
                                 gtitle="A: Summary Data - Train" , facets = FALSE, 
                                 pfas_nom = pfas_name )
  print(plt_train)

  ggsave(here ("output-plots", paste0( sa, "SummaryTrainDataboxplot", pfas_name,".pdf")), plt_train,dpi=600)
Saving 6.5 x 3.5 in image
  ggsave(here ("output-plots", paste0( sa, "SummaryTrainDataboxplot", pfas_name,".png")), plt_train,dpi=600)
Saving 6.5 x 3.5 in image
###  make Test plot
df_d_test <- df_check %>%   
    filter((Train_Test == "Test") & 
             ((Output_Var == "M_Cbgd_Css") | (Output_Var == "M_Cserum")))  %>%
     mutate_if(is.factor, as.character) %>%  # drop factor levels unused
     mutate(Dataset.Time = factor(Dataset.Time)) 

aes_lut_df_d_test <-  df_d_test %>% select(City, datatype,Time, Time.desc, legend_label) %>% 
   inner_join(aes_lut  ) %>% 
   select(-Train_Test) %>% ungroup () %>% unique ()  
Joining, by = c("City", "datatype", "Time", "Time.desc", "legend_label")
plt_test <- plot_sum_boxplot(dframe = df_d_test, aes_lut= aes_lut_df_d_test, 
                             gtitle="B: Summary Data - Test", facets = FALSE, pfas_nom = pfas_name)
  print(plt_test)

  ggsave(here ("output-plots",paste0( sa, "SummaryTestDataboxplot",pfas_name,".pdf")), plt_test,dpi=600)  
Saving 6.5 x 3.5 in image
  ggsave(here ("output-plots",paste0( sa, "SummaryTestDataboxplot",pfas_name,".png")), plt_test,dpi=600)  
Saving 6.5 x 3.5 in image

PFHxS

Background posteriors

Shows shift in background estimate.

gmscale<-0.8

dat <- multicheck$parms.samp[,grep("M_ln_Cbgd",names(multicheck$parms.samp))]
datasetnames <- as.character(unique(calibdata$dataset))
datasetnames <- gsub(" Train","-Train",datasetnames)
datasetnames <- gsub(" Test","-Train",datasetnames)
datasetnames <- gsub(" M","",datasetnames)
datasetnames <- gsub(" F","",datasetnames)
datasetnames<-datasetnames[!duplicated(datasetnames)]
datasetnames <- datasetnames[grep("Train",datasetnames)]
names(dat) <- datasetnames
dat <- dat[,grep("Train",names(dat))]
dat.df <- pivot_longer(dat,1:ncol(dat))
dat.df <- rbind(dat.df,
                data.frame(name="Prior",value=rnorm(5000,m=log(gmscale),sd=0.4055)))
dat.df$name <- factor(dat.df$name,levels=rev(
                        c("Prior",datasetnames[grep("Train",datasetnames)])))
dat.df$value <- exp(dat.df$value)

p<-ggplot(dat.df)+
 # geom_violin(aes(x=name,y=value,fill=name=="Prior"))+
  geom_boxplot(aes(x=name,y=value,fill=name=="Prior"),outlier.shape=NA)+
  scale_y_log10()+coord_flip()+
  scale_fill_manual(name=NULL, 
                    values=c("#009988", "#EE7733" )) +
  theme_classic() +  
  theme(axis.title.y.left = element_blank())+
  geom_hline(yintercept = gmscale, color="darkgrey", linetype = 2, size = 1.25)+
  theme(legend.position="none",
      panel.background = element_rect(color="black",size=1))+
  ylab("Posterior shift in Background Concentration")

print(p)

ggsave(here ("output-plots",paste0( sa, "PFHxS_GM_Cbgd.pdf")) ,p,dpi=600)
Saving 5 x 6 in image
ggsave(here ("output-plots",paste0( sa, "PFHxS_GM_Cbgd.png")) ,p,dpi=600)
Saving 5 x 6 in image

Half-life

For PFHxS, the population GM of the half-life has a posterior distribution that is narrower than the prior, with a posterior median (95% CI) estimate of 3.06 (2.16-4.37) years. The population GSD posterior is larger than the prior at 1.47(1.44-1.75).

dat <- multicheck$parms.samp[,c("M_ln_k.1.","V_ln_k.1.", "M_ln_Vd.1.", "SD_ln_Vd.1.")]
names(dat) <- c("M_ln_k(1)","V_ln_k(1)", "M_ln_Vd(1)", "SD_ln_Vd(1)")
  
set.seed(3.14159)
dat$z_ln_k <- rnorm(nrow(dat))
dat$z_ln_Vd <- rnorm(nrow(dat))
dat %>% rename_()
dat$ln_k_i <- dat$`M_ln_k(1)` + sqrt(dat$`V_ln_k(1)`)*dat$z_ln_k
dat$ln_Vd_i <- dat$`M_ln_Vd(1)`+ dat$`SD_ln_Vd(1)`*dat$z_ln_Vd
linmod <- lm(ln_Vd_i ~ ln_k_i,data=dat)
ggplot(dat) + geom_point(aes(ln_k_i,ln_Vd_i)) + 
  labs(subtitle=paste("Adj R2 =",signif(summary(linmod)$adj.r.squared,2)))

Check normality

qqnorm(dat$ln_k_i,main="ln k Q-Q Normal")
qqline(dat$ln_k_i,col="red")

plot(ecdf(dat$ln_k_i))
x <- seq(-3,1,0.01)
m_ln_k_i <-   mean(dat$ln_k_i)
sd_ln_k_i <- sd(dat$ln_k_i)
lines(x,pnorm(x,mean=m_ln_k_i,sd=sd_ln_k_i),col="red")
text(m_ln_k_i-2*sd_ln_k_i,0.9,paste("m =",signif(m_ln_k_i,4),"\nsd =",signif(sd_ln_k_i,4)))

qqnorm(dat$ln_Vd_i,main="ln Vd Q-Q Normal")
qqline(dat$ln_Vd_i,col="red")

plot(ecdf(dat$ln_Vd_i))
x <- seq(-3,1,0.01)
m_ln_Vd_i <- mean(dat$ln_Vd_i)
sd_ln_Vd_i <- sd(dat$ln_Vd_i)

lines(x,pnorm(x,mean=m_ln_Vd_i,sd=sd_ln_Vd_i),col="red")
text(m_ln_Vd_i-2*sd_ln_Vd_i,0.9,paste("m =",signif(m_ln_Vd_i,4),"\nsd =",signif(sd_ln_Vd_i,4)))

Calculate table values for individual-level

hl_i <- log(2)/ exp(dat$ln_k_i) # individual half-life 
med_hl_i <- paste(signif (median (hl_i), 3)) # median of individual half-life
ci_med_hl_i <-   paste(signif (quantile(hl_i, prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual halflife
ci98_med_hl_i <-   paste(signif (quantile(hl_i, prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual halflife
gm_hl_i <- paste(signif (exp(mean(log(hl_i))), 3)) # gm (which should be really close)
gsd_hl_i <- paste(signif (exp(sd(log(hl_i))), 3)) # gsd individual

med_Vd_i <- paste(signif (median(exp(dat$ln_Vd_i)), 3)) # median individual Vd
ci_med_Vd_i <-paste(signif (quantile(exp(dat$ln_Vd_i), prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual Vd
ci98_med_Vd_i <-paste(signif (quantile(exp(dat$ln_Vd_i), prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual Vd
gm_vd_i <- paste(signif (exp(mean(dat$ln_Vd_i)), 3)) # gm (which should be really close)
gsd_vd_i<- paste(signif (exp(sd(dat$ln_Vd_i)), 3)) # gsd indiv

med_CL_i <- paste(signif (median(exp(dat$ln_Vd_i+dat$ln_k_i)), 3)) # median individual CL
ci_med_CL_i <-paste(signif (quantile(exp(dat$ln_Vd_i+dat$ln_k_i), prob=c(0.025,0.975)), 3),collapse="-") # 95ci med individual CL
ci98_med_CL_i <-paste(signif (quantile(exp(dat$ln_Vd_i+dat$ln_k_i), prob=c(0.01,0.99)), 3),collapse="-") # 98ci med individual CL
gm_CL_i <- paste(signif (exp(mean(dat$ln_Vd_i+dat$ln_k_i)), 3)) # gm (which should be really close)
gsd_CL_i<- paste(signif (exp(sd(dat$ln_Vd_i+dat$ln_k_i)), 3)) # gsd indiv
PFHxS_priors <- data.frame(
  halflife_GM= log(2)/rlnorm(50000,
                             meanlog=-2.03422,sdlog=0.4055))
M_k <- exp(as.numeric(dat$`M_ln_k(1)`))
PFHxS_halflife_GM <- log(2)/M_k

PFHxS_hlgm_pr_med <- signif(median(PFHxS_priors$halflife_GM,3))
PFHxS_hlgm_pr_med_95ci <-paste(signif(quantile(PFHxS_priors$halflife_GM,
                                            prob=c(0.025,0.975)),
                                   3),
                            collapse="-")

PFHxS_hl_median_gm <- signif(median(PFHxS_halflife_GM),3)
PFHxS_hl_median_gm_95ci <- paste(signif(quantile(PFHxS_halflife_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(halflife_GM, color = "Prior"),data=PFHxS_priors,geom="line",size=2)+
  stat_density(aes(PFHxS_halflife_GM, stat(density),color="Posterior"),geom="line",size=1.5 )+
  xlim(0,15)+
  labs(title = bquote("G: PFHxS"~T[1/2]~"Population GM")  ,
       subtitle=paste("Posterior Median (95% CI): ",
                      PFHxS_hl_median_gm," (",
                      PFHxS_hl_median_gm_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GM"~T[1/2]~"(yrs)")) +
  scale_color_manual(name=NULL,#
                    values=c(Prior="#009988", Posterior="#EE7733" )) + 
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)
Warning: Removed 250 rows containing non-finite values (stat_density).
Warning: Removed 6 rows containing non-finite values (stat_density).

ggsave(here ("output-plots",paste0( sa, "PFHxS_hl_gm.pdf")),p,dpi=600)
Saving 4 x 2.5 in image
Warning: Removed 250 rows containing non-finite values (stat_density).

Warning: Removed 6 rows containing non-finite values (stat_density).
ggsave(here ("output-plots",paste0( sa, "PFHxS_hl_gm.png")),p,dpi=600)
Saving 4 x 2.5 in image
Warning: Removed 250 rows containing non-finite values (stat_density).

Warning: Removed 6 rows containing non-finite values (stat_density).
PFHxS_priors$halflife_GSD =  exp(sqrt(exp(rnorm(50000,m=log(0.2),sd=log(1.275))))) 
PFHxS_halflife_GSD <- exp(sqrt(dat$`V_ln_k(1)`))

PFHxS_hlgsd_pr_med <- signif(median(PFHxS_priors$halflife_GSD,3))
PFHxS_hlgsd_pr_med_95ci <-paste(signif(quantile(PFHxS_priors$halflife_GSD,
                                            prob=c(0.025,0.975)),
                                   3),
                            collapse="-")
PFHxS_hl_gsd_med <- signif(median(PFHxS_halflife_GSD),3)
PFHxS_hl_gsd_med_95ci <- paste(signif(quantile(PFHxS_halflife_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")
p<-ggplot()+
  stat_density(aes(halflife_GSD, color = "Prior"),data=PFHxS_priors,geom="line", size=2)+
  stat_density(aes(PFHxS_halflife_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("H: PFHxS"~T[1/2]~"Population GSD"),  
       subtitle=paste("Posterior Median (95% CI): ",
                      PFHxS_hl_gsd_med," (",
                      PFHxS_hl_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~T[1/2]))+
  scale_color_manual(name=NULL,#
                    values=c(Prior="#009988", Posterior="#EE7733" )) + 
   theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFHxS_hl_gsd.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFHxS_hl_gsd.png")) ,p,dpi=600)

Volume of distribution

For PFHxS, the data were not particularly informative, but slightly increased the estimate of the median to 0.308(0.223-0.548) slightly compared to the case where Cbgd was considered to be entirely from non-drinking water sources. They were not informative as to the population GSD, with the posterior distributions essentially unchanged from the priors.

PFHxS_priors$Vd_GM <- rlnorm(50000,
                             meanlog=-1.38629,
                             sdlog=0.2624)
PFHxS_Vd_GM <- exp(dat$`M_ln_Vd(1)`)

 

PFHxS_vd_gm_pr_med <- signif(median(PFHxS_priors$Vd_GM,3))
PFHxS_vd_gm_pr_med_95ci <- paste(signif(quantile(PFHxS_priors$Vd_GM,
                                            prob=c(0.025,0.975)), 3), collapse="-")
PFHxS_vd_gm_med <- signif(median(PFHxS_Vd_GM),3)
PFHxS_vd_gm_med_95ci <- paste(signif(quantile(PFHxS_Vd_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(Vd_GM, color = "Prior"),data=PFHxS_priors,geom="line",size=2)+
  stat_density(aes(PFHxS_Vd_GM,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(0,1)+labs(title = bquote("G: PFHxS"~V[d]~"Population GM"),
                 subtitle=paste("Posterior Median (95% CI): ",
                                PFHxS_vd_gm_med," (", 
                                PFHxS_vd_gm_med_95ci,")",sep=""))+
   xlab(bquote("Population GM"~V[d]~"(l/kg)"))+
  scale_color_manual(name=NULL,#
                    values=c(Prior="#009988", Posterior="#EE7733" )) +  
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFHxS_vd_gm.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFHxS_vd_gm.png")) ,p,dpi=600)
PFHxS_priors$Vd_GSD = exp(abs(rnorm(50000,sd=0.17)))
PFHxS_Vd_GSD <- exp(dat$`SD_ln_Vd(1)`)

PFHxS_vd_gsd_pr_med <- signif(median(PFHxS_priors$Vd_GSD,3))
PFHxS_vd_gsd_pr_med_95ci <- paste(signif(quantile(PFHxS_priors$Vd_GSD,
                                            prob=c(0.025,0.975)), 3), collapse="-")

PFHxS_vd_gsd_med <- signif(median(PFHxS_Vd_GSD),3)
PFHxS_vd_gsd_med_95ci <- paste(signif(quantile(PFHxS_Vd_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(Vd_GSD, color = "Prior"),data=PFHxS_priors,geom="line",size=2)+
  stat_density(aes(PFHxS_Vd_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("H: PFHxS"~V[d]~"Population GSD "),
       subtitle=paste("Posterior Median (95% CI): ",
                      PFHxS_vd_gsd_med," (",
                      PFHxS_vd_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~V[d]))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) + 
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa,"PFHxS_vd_gsd.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa,"PFHxS_vd_gsd.png")) ,p,dpi=600)

Clearance

Cl is k * Vd

PFHxS_priors$CL_GM <- PFHxS_priors$Vd_GM * (log(2)/PFHxS_priors$halflife_GM)
PFHxS_CL_GM <- exp(dat$`M_ln_Vd(1)` + dat$`M_ln_k(1)`)

PFHxS_cl_gm_pr_med <- signif(median(PFHxS_priors$CL_GM,3))
PFHxS_cl_gm_pr_med_95ci <- paste(signif(quantile(PFHxS_priors$CL_GM,
                                            prob=c(0.025,0.975)), 3), collapse="-")
PFHxS_cl_gm_med <- signif(median(PFHxS_CL_GM),3)
PFHxS_cl_gm_med_95ci <- paste(signif(quantile(PFHxS_CL_GM,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(CL_GM, color = "Prior"),data=PFHxS_priors,geom="line",size=2)+
  stat_density(aes(PFHxS_CL_GM,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(0,0.25)+labs(title = "D: PFHxS Clearance Pop. GM ",subtitle=paste("Posterior Median (95% CI): ",
                                                                    PFHxS_cl_gm_med," (",
                                                                    PFHxS_cl_gm_med_95ci,
                                                                    ")",sep=""))+
  xlab("Pop. GM CL (l/(kg-yr))")+
  scale_color_manual(name=NULL,#
                    values=c(Prior="#009988", Posterior="#EE7733" )) +  
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa, "PFHxS_CL_gm.pdf")), p,dpi=600)
ggsave(here ("output-plots",paste0( sa, "PFHxS_CL_gm.png")), p,dpi=600)
PFHxS_priors$CL_GSD = exp(sqrt(log(PFHxS_priors$Vd_GSD)^2 + 
  log(PFHxS_priors$halflife_GSD)^2))
PFHxS_CL_GSD <- exp(sqrt(log(PFHxS_Vd_GSD)^2 + 
  log(PFHxS_halflife_GSD)^2))

PFHxS_CL_gsd_pr_med <- signif(median(PFHxS_priors$CL_GSD,3))
PFHxS_CL_gsd_pr_med_95ci <- paste(signif(quantile(PFHxS_priors$CL_GSD,
                                            prob=c(0.025,0.975)), 3), collapse="-")

PFHxS_CL_gsd_med <- signif(median(PFHxS_CL_GSD),3)
PFHxS_CL_gsd_med_95ci <- paste(signif(quantile(PFHxS_CL_GSD,
                                            prob=c(0.025,0.975)),3),collapse="-")

p<-ggplot()+
  stat_density(aes(CL_GSD, color = "Prior"),data=PFHxS_priors,geom="line",size=2)+
  stat_density(aes(PFHxS_CL_GSD,stat(density), color = "Posterior"),geom="line",size=1.5)+
  xlim(1,3)+
  labs(title = bquote("H: PFHxS"~CL~"Population GSD "),
       subtitle=paste("Posterior Median (95% CI): ",
                      PFHxS_CL_gsd_med," (",
                      PFHxS_CL_gsd_med_95ci,
                      ")",sep=""))+
  xlab(bquote("Population GSD"~CL))+
  scale_color_manual(name=NULL, 
                     values=c(Prior="#009988", Posterior="#EE7733" )) + 
  theme_classic() +  
  theme(legend.title = element_blank(),legend.position=c(0.8,0.7),
      panel.background = element_rect(color="black",size=1),
      legend.background = element_rect(fill="transparent", color=NA))
print(p)

ggsave(here ("output-plots",paste0( sa,"PFHxS_CL_gsd.pdf")) ,p,dpi=600)
ggsave(here ("output-plots",paste0( sa,"PFHxS_CL_gsd.png")) ,p,dpi=600)

Table significant digit values

PFHxS_hlgm_pr_med <- paste(signif(PFHxS_hlgm_pr_med, 3))
PFHxS_hl_median_gm<- paste(signif(PFHxS_hl_median_gm, 3))
PFHxS_hlgsd_pr_med<- paste(signif(PFHxS_hlgsd_pr_med, 3))
PFHxS_hl_gsd_med<- paste(signif(PFHxS_hl_gsd_med, 3))
PFHxS_vd_gm_pr_med<- paste(signif(PFHxS_vd_gm_pr_med, 3))
PFHxS_vd_gm_med<- paste(signif(PFHxS_vd_gm_med, 3))
PFHxS_vd_gsd_pr_med<- paste(signif(PFHxS_vd_gsd_pr_med, 3))
PFHxS_vd_gsd_med<- paste(signif(PFHxS_vd_gsd_med, 3))
PFHxS_cl_gm_pr_med<- paste(signif(PFHxS_cl_gm_pr_med, 3))
PFHxS_cl_gm_med<- paste(signif(PFHxS_cl_gm_med, 3))

Population median estimates [95% CI]

Parameter Prior GM Posterior GM Prior GSD Posterior GSD
Half-life (years) 5.29 8.3 1.56 1.57
HL [95% CI] [2.39-11.8] [5.38-13.5] [1.42-1.77] [1.42-1.77]
Volume of distribution 0.25 0.286 1.12 1.11
\(V_D\) [95% CI] [0.149-0.418] [0.173-0.456] [1.01-1.46] [1-1.45]
Clearance 0.0326 0.0246
\(CL\) [95% CI] [0.0126-0.0847] [0.0121-0.0393] [] []

Individual Posterior estimates

Parameter median GM [95% CI] [[98% CI]] GM calculator input GSD individual
Half-life (years) 8.12 [ 2.79-21.6 ] [[ 2.19-24.8 ]] 8.2 1.68
Volume of distribution \(V_D\) 0.281 [ 0.161-0.46 ] [[ 0.14-0.561 ]] 0.281 1.32
Clearance (L/kg-yr) 0.0224 [ 0.00751-0.078 ] [[ 0.00648-0.101 ]] 0.0237 1.79

Session information

─ Session info ───────────────────────────────────────────────────────────────
 setting  value                                      
 version  R version 4.0.5 (2021-03-31)               
 os       Red Hat Enterprise Linux Server 7.9 (Maipo)
 system   x86_64, linux-gnu                          
 ui       X11                                        
 language (EN)                                       
 collate  en_US.UTF-8                                
 ctype    en_US.UTF-8                                
 tz       America/New_York                           
 date     2022-01-23                                 

─ Packages ───────────────────────────────────────────────────────────────────
 package     * version date       lib source        
 assertthat    0.2.1   2019-03-21 [2] CRAN (R 4.0.5)
 backports     1.4.0   2021-11-23 [1] CRAN (R 4.0.5)
 bayesplot   * 1.8.0   2021-01-10 [2] CRAN (R 4.0.5)
 broom         0.7.10  2021-10-31 [1] CRAN (R 4.0.5)
 bslib         0.2.4   2021-01-25 [2] CRAN (R 4.0.5)
 cachem        1.0.4   2021-02-13 [2] CRAN (R 4.0.5)
 callr         3.7.0   2021-04-20 [1] CRAN (R 4.0.5)
 cellranger    1.1.0   2016-07-27 [2] CRAN (R 4.0.5)
 cli           3.1.0   2021-10-27 [1] CRAN (R 4.0.5)
 coda        * 0.19-4  2020-09-30 [2] CRAN (R 4.0.5)
 codetools     0.2-18  2020-11-04 [2] CRAN (R 4.0.5)
 colorspace    2.0-2   2021-06-24 [1] CRAN (R 4.0.5)
 crayon        1.4.2   2021-10-29 [1] CRAN (R 4.0.5)
 DBI           1.1.1   2021-01-15 [2] CRAN (R 4.0.5)
 dbplyr        2.1.1   2021-04-06 [1] CRAN (R 4.0.5)
 desc          1.3.0   2021-03-05 [2] CRAN (R 4.0.5)
 devtools      2.3.2   2020-09-18 [2] CRAN (R 4.0.5)
 digest        0.6.29  2021-12-01 [1] CRAN (R 4.0.5)
 dplyr       * 1.0.7   2021-06-18 [1] CRAN (R 4.0.5)
 ellipsis      0.3.2   2021-04-29 [1] CRAN (R 4.0.5)
 evaluate      0.14    2019-05-28 [2] CRAN (R 4.0.5)
 fansi         0.5.0   2021-05-25 [1] CRAN (R 4.0.5)
 farver        2.1.0   2021-02-28 [2] CRAN (R 4.0.5)
 fastmap       1.1.0   2021-01-25 [2] CRAN (R 4.0.5)
 forcats     * 0.5.1   2021-01-27 [2] CRAN (R 4.0.5)
 fs            1.5.1   2021-11-30 [1] CRAN (R 4.0.5)
 generics      0.1.1   2021-10-25 [1] CRAN (R 4.0.5)
 ggplot2     * 3.3.5   2021-06-25 [1] CRAN (R 4.0.5)
 ggridges      0.5.3   2021-01-08 [2] CRAN (R 4.0.5)
 ggsci       * 2.9     2018-05-14 [2] CRAN (R 4.0.5)
 glue          1.5.1   2021-11-30 [1] CRAN (R 4.0.5)
 gtable        0.3.0   2019-03-25 [2] CRAN (R 4.0.5)
 haven         2.4.3   2021-08-04 [1] CRAN (R 4.0.5)
 here        * 1.0.1   2020-12-13 [2] CRAN (R 4.0.5)
 highr         0.9     2021-04-16 [1] CRAN (R 4.0.5)
 hms           1.1.1   2021-09-26 [1] CRAN (R 4.0.5)
 htmltools     0.5.2   2021-08-25 [1] CRAN (R 4.0.5)
 httr          1.4.2   2020-07-20 [2] CRAN (R 4.0.5)
 jquerylib     0.1.4   2021-04-26 [1] CRAN (R 4.0.5)
 jsonlite      1.7.2   2020-12-09 [2] CRAN (R 4.0.5)
 khroma      * 1.5.0   2021-04-23 [1] CRAN (R 4.0.5)
 knitr         1.36    2021-09-29 [1] CRAN (R 4.0.5)
 labeling      0.4.2   2020-10-20 [2] CRAN (R 4.0.5)
 lattice       0.20-41 2020-04-02 [2] CRAN (R 4.0.5)
 lifecycle     1.0.1   2021-09-24 [1] CRAN (R 4.0.5)
 lubridate     1.8.0   2021-10-07 [1] CRAN (R 4.0.5)
 magrittr      2.0.1   2020-11-17 [2] CRAN (R 4.0.5)
 memoise       2.0.0   2021-01-26 [2] CRAN (R 4.0.5)
 modelr        0.1.8   2020-05-19 [2] CRAN (R 4.0.5)
 munsell       0.5.0   2018-06-12 [2] CRAN (R 4.0.5)
 pillar        1.6.4   2021-10-18 [1] CRAN (R 4.0.5)
 pkgbuild      1.2.0   2020-12-15 [2] CRAN (R 4.0.5)
 pkgconfig     2.0.3   2019-09-22 [2] CRAN (R 4.0.5)
 pkgload       1.2.0   2021-02-23 [2] CRAN (R 4.0.5)
 plyr          1.8.6   2020-03-03 [2] CRAN (R 4.0.5)
 prettyunits   1.1.1   2020-01-24 [2] CRAN (R 4.0.5)
 pROC          1.18.0  2021-09-03 [1] CRAN (R 4.0.5)
 processx      3.5.2   2021-04-30 [1] CRAN (R 4.0.5)
 ps            1.6.0   2021-02-28 [2] CRAN (R 4.0.5)
 purrr       * 0.3.4   2020-04-17 [2] CRAN (R 4.0.5)
 R6            2.5.1   2021-08-19 [1] CRAN (R 4.0.5)
 ragg          1.1.2   2021-03-17 [2] CRAN (R 4.0.5)
 Rcpp          1.0.7   2021-07-07 [1] CRAN (R 4.0.5)
 readr       * 2.1.1   2021-11-30 [1] CRAN (R 4.0.5)
 readxl        1.3.1   2019-03-13 [2] CRAN (R 4.0.5)
 remotes       2.3.0   2021-04-01 [2] CRAN (R 4.0.5)
 reprex        2.0.1   2021-08-05 [1] CRAN (R 4.0.5)
 reshape2    * 1.4.4   2020-04-09 [2] CRAN (R 4.0.5)
 rlang         0.4.12  2021-10-18 [1] CRAN (R 4.0.5)
 rmarkdown     2.11    2021-09-14 [1] CRAN (R 4.0.5)
 rprojroot     2.0.2   2020-11-15 [2] CRAN (R 4.0.5)
 rstudioapi    0.13    2020-11-12 [2] CRAN (R 4.0.5)
 rvest         1.0.2   2021-10-16 [1] CRAN (R 4.0.5)
 sass          0.3.1   2021-01-24 [2] CRAN (R 4.0.5)
 scales      * 1.1.1   2020-05-11 [2] CRAN (R 4.0.5)
 sessioninfo   1.1.1   2018-11-05 [2] CRAN (R 4.0.5)
 stringi       1.7.6   2021-11-29 [1] CRAN (R 4.0.5)
 stringr     * 1.4.0   2019-02-10 [2] CRAN (R 4.0.5)
 systemfonts   1.0.3   2021-10-13 [1] CRAN (R 4.0.5)
 testthat      3.0.2   2021-02-14 [2] CRAN (R 4.0.5)
 textshaping   0.3.3   2021-03-16 [2] CRAN (R 4.0.5)
 tibble      * 3.1.6   2021-11-07 [1] CRAN (R 4.0.5)
 tidyr       * 1.1.4   2021-09-27 [1] CRAN (R 4.0.5)
 tidyselect    1.1.1   2021-04-30 [1] CRAN (R 4.0.5)
 tidyverse   * 1.3.1   2021-04-15 [1] CRAN (R 4.0.5)
 tzdb          0.2.0   2021-10-27 [1] CRAN (R 4.0.5)
 usethis       2.0.1   2021-02-10 [2] CRAN (R 4.0.5)
 utf8          1.2.2   2021-07-24 [1] CRAN (R 4.0.5)
 vctrs         0.3.8   2021-04-29 [1] CRAN (R 4.0.5)
 withr         2.4.3   2021-11-30 [1] CRAN (R 4.0.5)
 xfun          0.28    2021-11-04 [1] CRAN (R 4.0.5)
 xml2          1.3.3   2021-11-30 [1] CRAN (R 4.0.5)
 yaml          2.2.1   2020-02-01 [2] CRAN (R 4.0.5)
 yardstick   * 0.0.9   2021-11-22 [1] CRAN (R 4.0.5)

[1] /home/ad.abt.local/layc/R/x86_64-pc-linux-gnu-library/4.0
[2] /opt/R/4.0.5/lib64/R/library
LS0tCnRpdGxlOiAiUEZIeFMgMSBjb21wYXJ0bWVudCBQbG90cyAodjgpIgphdXRob3I6ICJXZWloc3VlaCBDaGl1LCBDbGFpcmUgTGF5LCBQYXJrZXIgTWFsZWsiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVGJylgIgprbml0OiAoZnVuY3Rpb24oaW5wdXRGaWxlLCBlbmNvZGluZykge291dGRpciA9IGZpbGUucGF0aChkaXJuYW1lKGlucHV0RmlsZSksICdtYXJrZG93bicsIHBhc3RlMChmb3JtYXQoU3lzLnRpbWUoKSwgJyVGJykpKTsgaWYoIWRpci5leGlzdHMob3V0ZGlyKSl7ZGlyLmNyZWF0ZShvdXRkaXIpfTsgcm1hcmtkb3duOjpyZW5kZXIoaW5wdXRGaWxlLCBlbmNvZGluZyA9IGVuY29kaW5nLCBvdXRwdXRfZm9ybWF0ID0gJ2FsbCcsIG91dHB1dF9kaXIgPSBvdXRkaXIpIH0pCm91dHB1dDoKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZGZfcHJpbnQ6IGthYmxlCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA1Ci0tLQoKYGBge3Igc2V0dXB9CmxpYnJhcnkoY29kYSkKbGlicmFyeShiYXllc3Bsb3QpIApsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkoa2hyb21hKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeSh5YXJkc3RpY2spICMgZm9yIHF1aWNrIHJtc2UKbGlicmFyeShoZXJlKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGRwaSA9IDMwMCApCmBgYAoKU2V0IHVwIE1DU2ltIGZpbGUKCmBgYHtyIG1jc2ltfQojIHRoaXMgbWFya2Rvd24gZmlsZSBtdXN0IGJlIHNhdmVkIGluIHRvcCBsZXZlbCBkaXJlY3RvcnkgZm9yIHRoZSBmb2xsb3dpbmcgdG8gd29yazsgdGhlIG1jc2ltIGNvZGUgZGVwZW5kcyBvbiBnZXR3ZCByZXN1bHRzLgptZGlyIDwtICJNQ1NpbSIKc291cmNlKGhlcmU6OmhlcmUobWRpciwic2V0dXBfTUNTaW0uUiIpKQojIE1ha2UgbW9kLmV4ZSAodXNlZCB0byBjcmVhdGUgbWNzaW0gZXhlY3V0YWJsZSBmcm9tIG1vZGVsIGZpbGUpCm1ha2Vtb2QoKSAKYGBgCgojIyBTZXQgZmlsZW5hbWVzIGFuZCBsb2FkIGRhdGEKCgpgYGB7ciBNQ01DICBtb2RlbCBmaWxlLCBpbmNsdWRlPUZBTFNFfQpzZXQuc2VlZCgzMTQxNTkpCnNhIDwtICJDYmdkLTgwXyIgIyBBREQgc2Vuc2l0aXZpdHkgdGVzdCB0YWcgdG8gcGxvdCBmaWxlbmFtZXMKIyBNX2xuX0NiZ2Rfc2MgdG8gYmUgY2VudGVyZWQgb24gbG4oMC44KSBpbnN0ZWFkIG9mIDAgKGRlY3JlYXNlZCBieSAyMCUpCiMgTWFrZSBtb2RlbCBleGVjdXRhYmxlCm1vZGVsX2ZpbGU8LSAiUEZBU18xY3B0X3Y4LnBvcC5NQ01DLm1vZGVsLlIiCm1ha2VtY3NpbShtb2RlbF9maWxlKQoKaW5fZmlsZSA8LSAiUEZIeFNfMWNwdF92OC5Qb3BNQ01DX01lYW5JbmRpdlRyYWluVGVzdC5pbi5SIiAKcGZhc19uYW1lIDwtIGdzdWIoIl8xY3B0X3Y4LlBvcE1DTUNfTWVhbkluZGl2VHJhaW5UZXN0LmluLlIiLCAiIiwgaW5fZmlsZSkKCnNhbXBzIDwtIGRhdGEuZnJhbWUoKQpjaGVja3MgPC0gZGF0YS5mcmFtZSgpCnNhbXBzLmxpc3QgPC0gbGlzdCgpCmZvciAoY2hhaW5udW0gaW4gMTo0KSB7CiAgb25lY2hhaW4gPC0gcmVhZC5kZWxpbShzdWIoIi5pbi5SIixwYXN0ZTAoY2hhaW5udW0sIi5vdXQiKSxpbl9maWxlKSkKICBzYW1wcy5saXN0W1tjaGFpbm51bV1dPC1tY21jKG9uZWNoYWluW2Zsb29yKG5yb3cob25lY2hhaW4pIC8gMik6bnJvdyhvbmVjaGFpbiksIC0xXSkKICBzYW1wcyA8LSByYmluZChzYW1wcyxzYW1wcy5saXN0W1tjaGFpbm51bV1dKQogIG9uZWNoZWNrIDwtIHJlYWQuZGVsaW0oc3ViKCIuaW4uUiIscGFzdGUwKGNoYWlubnVtLCIuY2hlY2sub3V0IiksaW5fZmlsZSkpCiAgb25lY2hlY2skQ2hhaW4gPC0gY2hhaW5udW0KICBjaGVja3MgPC0gcmJpbmQoY2hlY2tzLG9uZWNoZWNrKQp9CnNhbXBzLm1jbWNsaXN0IDwtIGFzLm1jbWMubGlzdChzYW1wcy5saXN0KQoKbG9hZCgiUEZIeFNfMWNwdF92OF9tdWx0aWNoZWNrLlJkYXRhIikgCmBgYAoKIyMgU2V0IHVwIGRhdGFzZXQKCmBgYHtyIGRhdGFzZXQtTFVULCBjYWNoZSA9IFRSVUV9CmlkX2x1dCA8LSBtdWx0aWNoZWNrJGRmX2NoZWNrICU+JSBzZWxlY3QoTGV2ZWwpICU+JSB1bmlxdWUgKCkgICU+JQogIG11dGF0ZShkYXRhc2V0ID0gYyggCiAgICByZXAoIkRlY2F0dXIgTSBUcmFpbiIsIDkpLAogICAgcmVwKCJEZWNhdHVyIEYgVHJhaW4iLCA5KSwKICAgIHJlcCgiRGVjYXR1ciBNIFRlc3QiLCA5KSwKICAgIHJlcCgiRGVjYXR1ciBGIFRlc3QiLCAxMCksCiAgICAnUGF1bHNib3JvLVRyYWluJywnSG9yc2hhbS1UcmFpbicsCiAgICAnV2FybWluc3Rlci1UZXN0JywnV2FycmluZ3Rvbi1UcmFpbicpLCAKICAgIFNleCA9IGMoIAogICAgcmVwKCJNIiwgOSksCiAgICByZXAoIkYiLCA5KSwKICAgIHJlcCgiTSIsIDkpLAogICAgcmVwKCJGIiwgMTApLAogICAgJ01peGVkJywgJ01peGVkJywgICdNaXhlZCcsICdNaXhlZCcpLAogICAgQ2l0eSA9IGMoIAogICAgcmVwKCJEZWNhdHVyIiwgMTgpLAogICAgcmVwKCJEZWNhdHVyIiwgMTkpLAogICAgJ1BhdWxzYm9ybycsJ0hvcnNoYW0nLCdXYXJtaW5zdGVyJywnV2FycmluZ3RvbicpLCAKICAgIFRyYWluX1Rlc3QgPSBjKCAKICAgIHJlcCgiVHJhaW4iLCA5KSwKICAgIHJlcCgiVHJhaW4iLCA5KSwKICAgIHJlcCgiVGVzdCIsIDkpLAogICAgcmVwKCJUZXN0IiwgMTApLAogICAgJ1RyYWluJywgJ1RyYWluJywgJ1Rlc3QnLCAnVGVzdCcpLAogICAgZGF0YXR5cGUgPSBjKAogICAgICByZXAoIkluZGl2aWR1YWwiLDkrOSs5KzEwKSwKICAgICAgcmVwKCJTdW1tYXJ5Iiw0KSksCiAgICBTaW11bGF0aW9uID0gcm93X251bWJlcigpLAogICAgdmFyaWFibGUgPSBwYXN0ZTAoZGF0YXNldCwgIiAiLFNpbXVsYXRpb24pKQoKaWRfbHV0JGRhdGFzZXQgPC0gZmFjdG9yKGlkX2x1dCRkYXRhc2V0LGxldmVscz0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiRGVjYXR1ciBNIFRyYWluIiwiRGVjYXR1ciBGIFRyYWluIiwiQXJuc2JlcmcgTSBUcmFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFybnNiZXJnIEYgVHJhaW4iLCJEZWNhdHVyIE0gVGVzdCIsIkRlY2F0dXIgRiBUZXN0IiwiQXJuc2JlcmcgTSBUZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXJuc2JlcmcgRiBUZXN0IiwiTWlubmVzb3RhIFRyYWluIiwiTWlubmVzb3RhIFRlc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMdWJlY2stQmFydGVsbC1UcmFpbicsICdMdWJlY2stQmFydGVsbC1UZXN0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTGl0dGxlIEhvY2tpbmctQmFydGVsbC1UcmFpbicsICdMaXR0bGUgSG9ja2luZy1CYXJ0ZWxsLVRlc3QnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMaXR0bGUgSG9ja2luZy1FbW1ldHQtVGVzdCcsJ1BhdWxzYm9yby1UcmFpbicsJ0hvcnNoYW0tVHJhaW4nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICdXYXJtaW5zdGVyLVRlc3QnLCdXYXJyaW5ndG9uLVRyYWluJykpCmlkX2x1dCRDaXR5IDwtIGZhY3RvcihpZF9sdXQkQ2l0eSxsZXZlbHMgPSAKICAgICAgICAgICAgICAgICAgICAgICAgYygiRGVjYXR1ciIsIkFybnNiZXJnIiwiTWlubmVzb3RhIiwnTHViZWNrLUJhcnRlbGwnLAogICAgICAgICAgICAgICAgICAgICAgICAgICdMaXR0bGUgSG9ja2luZy1CYXJ0ZWxsJywnTGl0dGxlIEhvY2tpbmctRW1tZXR0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAnUGF1bHNib3JvJywnSG9yc2hhbScsJ1dhcm1pbnN0ZXInLCdXYXJyaW5ndG9uJykpCiAKCmluZGl2X2x1dCA8LSBpZF9sdXQgJT4lIAogIGZpbHRlcihDaXR5ICVpbiUgYygiRGVjYXR1ciIpKSAlPiUKICBtdXRhdGUoICBkYXRhc2V0ID0gYXMuZmFjdG9yKGRhdGFzZXQpKQoKbnYgPC0gZGF0YS5mcmFtZShkYXRhc2V0ID11bmlxdWUoaW5kaXZfbHV0JGRhdGFzZXQpLCAKICAgICAgICAgICB2YXJpYWJsZT0gcmVwKCJQb3AgR00iLCA0KSwKICAgICAgICAgICB0eXBlPSByZXAoIlBvcCBHTSIsIDQpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmBgYAoKIyMgSW5kaXZpZHVhbCBwYXJhbWV0ZXJzCmBgYHtyIGluZGl2LXBhcm1zLCBjYWNoZSA9IFRSVUUsZmlnLmhlaWdodD0zLjUsZmlnLndpZHRoPTMuNSxkcGk9NjAwfQpzZXQuc2VlZCgzMTQxNTkpCgppbmRpdl9wYXJtcyA8LSBpbmRpdl9sdXQKbG5rcGFybW5hbWVzIDwtIHBhc3RlKCJsbl9rLiIsZ3N1YigiXyIsIi4iLGluZGl2X3Bhcm1zJExldmVsKSwiLiIsc2VwPSIiKQpsblZkcGFybW5hbWVzIDwtIHBhc3RlKCJsbl9WZC4iLGdzdWIoIl8iLCIuIixpbmRpdl9wYXJtcyRMZXZlbCksIi4iLHNlcD0iIikKCnBhcm1zYW1wIDwtIGFwcGx5KG11bHRpY2hlY2skcGFybXMuc2FtcCwyLHNhbXBsZSwxKQoKIyMgUmFuZG9tIHotc2NvcmUgZXN0aW1hdGUgb2YgZWFjaCBwYXJhbWV0ZXIKaW5kaXZfcGFybXMkbG5fay56LnNhbXAgPC0gcGFybXNhbXBbbG5rcGFybW5hbWVzXQppbmRpdl9wYXJtcyRsbl9WZC56LnNhbXAgPC0gcGFybXNhbXBbbG5WZHBhcm1uYW1lc10KCm5vcm1kIDwtIGRhdGEuZnJhbWUoeD1xbm9ybShwcG9pbnRzKDIwMCkpKQpub3JtZCR5IDwtIGRub3JtKG5vcm1kJHgpCgppcGxvdGs8LQogIGdncGxvdChzdWJzZXQoaW5kaXZfcGFybXMsVHJhaW5fVGVzdD09IlRyYWluIikpKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9bG5fay56LnNhbXAsYWZ0ZXJfc3RhdChkZW5zaXR5KSksYmlucz0xMCkrZmFjZXRfd3JhcCh+Q2l0eSxuY29sPTEpKwogICAgZ2VvbV9saW5lKGFlcyh4PXgseT15KSxkYXRhPW5vcm1kKSsKICAgIHhsYWIoIkluZGl2aWR1YWwgei1zY29yZXMgZm9yIGsiKSArIHRoZW1lX2J3KCkKCmlwbG90VmQ8LQogIGdncGxvdChzdWJzZXQoaW5kaXZfcGFybXMsVHJhaW5fVGVzdD09IlRyYWluIikpKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9bG5fVmQuei5zYW1wLGFmdGVyX3N0YXQoZGVuc2l0eSkpLGJpbnM9MTApK2ZhY2V0X3dyYXAofkNpdHksbmNvbD0xKSsKICAgIGdlb21fbGluZShhZXMoeD14LHk9eSksZGF0YT1ub3JtZCkrCiAgICB4bGFiKCJJbmRpdmlkdWFsIHotc2NvcmVzIGZvciBWZCIpICsgdGhlbWVfYncoKQoKcHJpbnQoaXBsb3RrKQpwcmludChpcGxvdFZkKQoKZ2dzYXZlKGZpbGUucGF0aCgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgIHBhc3RlMCggc2EsIkluZGl2X3pzY29yZXNfa19QRkh4Uy5wZGYiKSksaXBsb3RrLGRwaT02MDApCmdnc2F2ZShmaWxlLnBhdGgoIm91dHB1dC1wbG90cyIsCiAgICAgICAgICAgICBwYXN0ZTAoIHNhLCJJbmRpdl96c2NvcmVzX2tfUEZIeFMucG5nIikpLGlwbG90ayxkcGk9NjAwKQoKZ2dzYXZlKGZpbGUucGF0aCgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgIHBhc3RlMCggc2EsIkluZGl2X3pzY29yZXNfVmRfUEZIeFMucGRmIikpLGlwbG90VmQsZHBpPTYwMCkKZ2dzYXZlKGZpbGUucGF0aCgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgIHBhc3RlMCggc2EsIkluZGl2X3pzY29yZXNfVmRfUEZIeFMucG5nIikpLGlwbG90VmQsZHBpPTYwMCkKYGBgCgojIyBTY2F0dGVyIHBsb3Qgb2YgcHJlZGljdGlvbnMgKG1lZGlhbiBvZiBtdWx0aWNoZWNrIHNhbXBsZXMpIHZlcnN1cyBkYXRhLgoKVGhpcyBpcyBhIEZpZ3VyZSAyIHBhbmVsLiAgTmVlZGVkIHRvIHVzZSAic2NhbGU9MS4xIiBpbiBnZ3NhdmUgdG8gbWF0Y2ggUEZPQS4KCmBgYHtyIHByZWRpY3Rpb24tdmVyc3VzLWRhdGEgLCBjYWNoZSA9IFRSVUUsZmlnLmhlaWdodD0zLjUsZmlnLndpZHRoPTgsZHBpPTYwMH0KbnJvdyhtdWx0aWNoZWNrJGRmX2NoZWNrKQpucm93KGlkX2x1dCkKbXVsdGljaGVjayRkZl9jaGVjayAlPiUgbGVmdF9qb2luKGlkX2x1dCkgJT4lIG5yb3coKQoKbmFtZXMobXVsdGljaGVjayRkZl9jaGVjaykKCm11bHRpY2hlY2syIDwtIG11bHRpY2hlY2skZGZfY2hlY2sgJT4lIAogIGxlZnRfam9pbihpZF9sdXQsIGJ5ID0gYygiTGV2ZWwiLCAiU2ltdWxhdGlvbiIpKSU+JSAKICBncm91cF9ieV9hdCAoIHZhcnMoLVByZWRpY3Rpb24pKSAlPiUgCiAgc3VtbWFyaXNlKFByZWRpY3Rpb24gPSBtZWRpYW4oUHJlZGljdGlvbikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShDaXR5KSAlPiUgCiAgbXV0YXRlKFRyYWluX1Rlc3QgPSBmYWN0b3IoVHJhaW5fVGVzdCwgbGV2ZWxzID0gYygiVHJhaW4iLCAiVGVzdCIpKSwKICAgICAgICAgYENpdHkgKGRhdGF0eXBlKWAgPSBmYWN0b3IgKHBhc3RlMCgiXG4iLCBDaXR5LCAiXG4oIiwgZGF0YXR5cGUsICIpXG4iKSApLAogICAgICAgICBsYWJlbCA9IGNhc2Vfd2hlbihUcmFpbl9UZXN0PT0iVHJhaW4iIH4gIkc6IFBGSHhTIFRyYWluIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fVGVzdD09IlRlc3QiICB+ICJIOiBQRkh4UyBUZXN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICIiKSkKCiNkZWZpbmUgY29sb3IgZm9yIHRlc3RpbmcgYm94cGxvdHMKYnBfY29scyA8LSBjIChhcy5jaGFyYWN0ZXIgKGtocm9tYTo6Y29sb3VyKCJtdXRlZCIpKDkpKSAsICIjMTkxOTE5IikgICAKYnBfY29scyA8LWJwX2NvbHNbYygxLDcsMTA6OCldIyBwbG90X3NjaGVtZV9jb2xvdXJibGluZChicF9jb2xzKSAKCiMjIyBDcmVhdGUgYWVzdGhldGljcyBsb29rdXAKYWVzX2x1dCA8LSBtdWx0aWNoZWNrMiAlPiUgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShDaXR5LCBkYXRhdHlwZSwgIGBDaXR5IChkYXRhdHlwZSlgICkgJT4lIHN1bW1hcmlzZSAoKSAlPiUgdW5ncm91cCgpICU+JQogIG11dGF0ZSggY29scyA9IGJwX2NvbHMsIGNpdHlfZmlsbHMgPSAgIGJwX2NvbHMgLCAKICAgICAgICAgICMgZm9yIGluZGl2aWR1YWwgbGV2ZWwgb24gcG9pbnQgcGxvdCAobXVsdGljaGVjazIpLCBkYXJrZW4gb3V0bGluZXMgZm9yIHZpc2liaWxpdHksIHVzZSBzdGFuZGFyZCBjb2xvcnMgb3RoZXJ3aXNlCiAgICAgICAgIGNpdHlfb3V0bGluZXMgPSAgaWZfZWxzZShkYXRhdHlwZSA9PSAiSW5kaXZpZHVhbCIgICwgIGNvbG9yc3BhY2U6OmRhcmtlbihjaXR5X2ZpbGxzLCAwLjMpLCBjaXR5X2ZpbGxzKSAsICAKICAgICAgICAgc2hhcGVzID0gY2FzZV93aGVuKGRhdGF0eXBlID09ICJJbmRpdmlkdWFsIiAgJiBgQ2l0eWAgJWluJSBjKCdEZWNhdHVyJywgJ0FybnNiZXJnJywgJ01pbm5lc290YScpICAgfiAgMjMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhdHlwZSA9PSAiU3VtbWFyeSIgJmBDaXR5YCAlaW4lIGMoIkhvcnNoYW0iLCAiV2FybWluc3RlciIsICAiV2FycmluZ3RvbiIpIH4gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGF0eXBlID09ICJTdW1tYXJ5IiAmIGBDaXR5YCA9PSAiUGF1bHNib3JvIiB+IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMTggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksIAogICAgICAgICBzaXplID0gaWZfZWxzZShkYXRhdHlwZSA9PSJJbmRpdmlkdWFsIiwgMS43NSwgMi41ICkgKSAgCgoKc291cmNlKCBwYXN0ZTAoZ3N1YihiYXNlbmFtZShoZXJlKCkpLCAnc2hhcmVkX2Z1bmN0aW9ucycsIGhlcmUoKSksICcvcGxvdF9zY2F0dGVyX21jaGVjay5yJykpCgpwMiA8LSBwbG90X3NjYXR0ZXJfbWNoZWNrKGRmcmFtZSA9IG11bHRpY2hlY2syLCAgcGZhc19ub20gPSBwZmFzX25hbWUsIGFlc19sdXRfZm4gPSBhZXNfbHV0ICkKcHJpbnQocDIpIApnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIsIHBhc3RlMCggc2EsIm11bHRpY2hlY2twbG90XyIsIHBmYXNfbmFtZSwKICAgICAgICAgICAgICAgIi5wZGYiKSkscDIsZHBpPTYwMCwgc2NhbGU9MS4xKQoKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLCBwYXN0ZTAoIHNhLCJtdWx0aWNoZWNrcGxvdF8iLCBwZmFzX25hbWUsCiAgICAgICAgICAgICAgICIucG5nIikpLHAyLGRwaT02MDAsIHNjYWxlPTEuMSkKCm11bHRpY2hlY2syJFBGQVMgPC0gIlBGSHhTIgptdWx0aXBsb3Rfc2NhdHRlcl9kYXQgPC0gbGlzdChhZXNfbHV0ID0gYWVzX2x1dCwgbXVsdGljaGVjazIgPSBtdWx0aWNoZWNrMikgIyBzYXZlIG91dCBmb3IgdXNlIGluIGNvbW1iaW5lZCBwbG90CnNhdmUobXVsdGlwbG90X3NjYXR0ZXJfZGF0LCBmaWxlID0gICJwZmh4c19tdWx0aXBsb3Rfc2NhdHRlci5SZGF0YSIpCmBgYAoKIyMgUGFyc2UgbXVsdGljaGVjawoKYGBge3IgZG8tbXVsdGljaGVjaywgY2FjaGUgPSBUUlVFLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD0xOH0KCmRmX2NoZWNrIDwtIG11bHRpY2hlY2skZGZfY2hlY2sKZGZfY2hlY2sgPC0gc3Vic2V0KGRmX2NoZWNrLERhdGEgPiAwKSAKCm4xIDwtIG5yb3coZGZfY2hlY2spCmlkX2Noa3MgPC0gZGZfY2hlY2sgJT4lIHNlbGVjdChMZXZlbCkgJT4lIHVuaXF1ZSgpICU+JSBiaW5kX2NvbHMoaWRfbHV0KSAgJT4lCiAgbXV0YXRlKGRhdGFzZXQgPSBhcy5mYWN0b3IoZGF0YXNldCksIFNleCA9IGFzLmZhY3RvcihTZXgpLCBDaXR5ID0gYXMuZmFjdG9yKENpdHkpLCAKICAgICAgICAgVHJhaW5fVGVzdCA9IGFzLmZhY3RvcihUcmFpbl9UZXN0KSkKCmRmX2NoZWNrIDwtIGRmX2NoZWNrICU+JSBsZWZ0X2pvaW4oaWRfY2hrcyklPiUKICBtdXRhdGUoRGF0YXNldCA9IHBhc3RlKGFzLmNoYXJhY3RlcihkYXRhc2V0KSwgU2ltdWxhdGlvbiksCiAgICAgICAgIFNleCA9IG9yZGVyZWQoU2V4LCBsZXZlbHMgPSBjKCJNIiwgIkYiLCAiTWl4ZWQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTWFsZSIsICJGZW1hbGUiLCAiTWl4ZWQgKGFsbCBzZXhlcykiKSkpCm4yIDwtIG5yb3coZGZfY2hlY2spCmlmKG4xICE9IG4yKXByaW50KCJkdXBsaWNhdGVzIGNyZWF0ZWQgaW4gaWQtbHV0IGpvaW4iKQpgYGAKCgpgYGB7ciBkby1tdWx0aWNoZWNrLTIsIGNhY2hlID0gVFJVRSwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9MTh9CmRmX2NoZWNrJFRpbWUuZGVzYyA8LSBhcy5jaGFyYWN0ZXIocGFzdGUwKCJUPSIsZGZfY2hlY2skVGltZSkpCmRmX2NoZWNrJFRpbWUuZGVzY1tkZl9jaGVjayRUaW1lLmRlc2MgPT0gIlQ9MWUtMDYiXSA8LSAiU3RlYWR5U3RhdGUiCmRmX2NoZWNrJERhdGFzZXQuVGltZSA8LSBpbnRlcmFjdGlvbihkZl9jaGVjayREYXRhc2V0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfY2hlY2skVGltZS5kZXNjLGxleC5vcmRlcj1UUlVFKQpkZl9jaGVjayREYXRhc2V0LlRpbWUgPC0gZmFjdG9yKGRmX2NoZWNrJERhdGFzZXQuVGltZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9bGV2ZWxzKGRmX2NoZWNrJERhdGFzZXQuVGltZSkpCmNhbGliZGF0YSA8LSBkZl9jaGVja1ssbmFtZXMoZGZfY2hlY2spICE9ICJQcmVkaWN0aW9uIl0KY2FsaWJkYXRhIDwtIGNhbGliZGF0YVshZHVwbGljYXRlZChjYWxpYmRhdGEpLF0KcHJpbnQoY2FsaWJkYXRhKQogCiNNdWx0aWNoZWNrIHBsb3QKCiMgU3BsaXQgU3RlYWR5IFN0YXRlIEdyb3VwIGludG8gZGlmZmVyZW50IHBvcHVsYXRpb25zIGZvciBib3hwbG90IGdyb3VwaW5nCiNkZl9jaGVja1tkZl9jaGVjayRUaW1lLmRlc2MgPT0gIlN0ZWFkeVN0YXRlIiAmIGdyZXBsKCJMdWJlY2siLGRmX2NoZWNrJERhdGFzZXQpLF0kVGltZS5kZXNjIDwtICJMdWJlY2siCiNkZl9jaGVja1tkZl9jaGVjayRUaW1lLmRlc2MgPT0gIlN0ZWFkeVN0YXRlIiAmIGdyZXBsKCJMaXR0bGUgSG9ja2luZyIsZGZfY2hlY2skRGF0YXNldCksXSRUaW1lLmRlc2MgPC0gIkxpdHRsZSBIb2NraW5nIgpgYGAKTW9kaWZ5IGFlc3RoZXRpY3MgbG9va3VwIHRhYmxlIGZvciBib3hwbG90cyAKYGBge3IgbW9kLWFlcy1sdXR9CiMjICBhZGRpdGlvbmFsIHNvdXJjZSBhZXN0aGV0aWMgbG9va3VwIHRhYmxlIGZvciBncmV5LXNjYWxlIHRpbWUgKHllYXJzKTsgIG1lcmdlZCBsZWdlbmRzIHNhdmUgc3BhY2Ugb24gcGxvdHRpbmcgb3V0cHV0CnRpbWVzIDwtIGRmX2NoZWNrJT4lIHNlbGVjdChUaW1lLmRlc2MsIFRpbWUpICU+JSAgdW5pcXVlICgpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoVGltZSkgLCBncmV5ID0gZ3JleS5jb2xvcnMoc3RhcnQ9MSxlbmQ9MC40LCBuID0gbigpKSwKICAgICAgICAgYWxwaGEgPSAocmFuaykvOCkgJT4lIAogIHNlbGVjdCgtVGltZSkKIApkZl9jaGVjayA8LSBkZl9jaGVjayAlPiUgbXV0YXRlIChsZWdlbmRfbGFiZWwgPSAocGFzdGUwKENpdHksICJcbiIsIFRpbWUuZGVzYyApICkpICMgYWRkIGxlZ2VuZC1sYWJlbHMKYWVzX2x1dCA8LSBkZl9jaGVjayAlPiUgCiAgc2VsZWN0KENpdHksIFRyYWluX1Rlc3QsIGRhdGF0eXBlLFRpbWUsIFRpbWUuZGVzYywgbGVnZW5kX2xhYmVsKSAlPiUgdW5pcXVlICgpICU+JQogICBsZWZ0X2pvaW4oYWVzX2x1dFssIGMoIkNpdHkiLCAiY29scyIpXSwgYnkgPSAiQ2l0eSIpICU+JSB1bmdyb3VwICgpICU+JSB1bmlxdWUgKCklPiUKICAgbGVmdF9qb2luICh0aW1lcywgYnkgPSAiVGltZS5kZXNjIikgJT4lIAogICBhcnJhbmdlKGRhdGF0eXBlLCBDaXR5LCBUcmFpbl9UZXN0LCBUaW1lKSAgICAlPiUgCiAgIG11dGF0ZShhbHBoYSA9IGlmX2Vsc2UoQ2l0eSA9PSAiSG9yc2hhbSIsIGFscGhhLzIsIGFscGhhKSkgJT4lICMgb3RoZXJ3aXNlIHRvbyBkYXJrIHdpdGggdGhpcyBjb2xvcgogIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgCgpgYGAKCiMjIERlY2F0dXIgYm94cGxvdHMKCkNoYW5nZWQgZ3JleSBzdGFydCB0byAxIGluc3RlYWQgb2YgMC44LCBlbmQgYXQgMC42IGluc3RlYWQgb2YgMC40LgpDaGFuZ2VkIHNoYXBlIG9mIHN5bWJvbHMgc28gdGhleSBhcmUgZmlsbGVkLgoKYGBge3IgZG8tbXVsdGljaGVjay1kZWNhdHVyLCBjYWNoZSA9IFRSVUUsIGZpZy53aWR0aD02LjUsIGZpZy5oZWlnaHQ9My41LGRwaT02MDB9CiNHSAojIERlY2F0dXIgCgpkZl9kZWNhdCAgPC0gZGZfY2hlY2sgJT4lICAgCiAgZmlsdGVyKENpdHkgPT0gIkRlY2F0dXIiICYgVHJhaW5fVGVzdCAlaW4lIGMgKCJUcmFpbiIsICJUZXN0IikpICU+JSAKICBtdXRhdGUocGFuZWwgPSBvcmRlcmVkIChUcmFpbl9UZXN0LCBsZXZlbHMgPSBjICgiVHJhaW4iLCAiVGVzdCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJHOiBQRkh4UyBEZWNhdHVyIFRyYWluIiwgIkg6IFBGSHhTIERlY2F0dXIgVGVzdCIpICkpCgphZXNfbHV0X2RmX2RmX2RlY2F0IDwtIGFlc19sdXQgJT4lIAogIGZpbHRlcihDaXR5ID09ICJEZWNhdHVyIiAmIFRyYWluX1Rlc3QgJWluJSBjICgiVHJhaW4iLCAiVGVzdCIpKSAlPiUgCiAgbXV0YXRlX2lmKGlzLmZhY3RvciwgYXMuY2hhcmFjdGVyKSAKCnNvdXJjZSggcGFzdGUwKGdzdWIoYmFzZW5hbWUoaGVyZSgpKSwgJ3NoYXJlZF9mdW5jdGlvbnMnLCBoZXJlKCkpLCAnL3Bsb3Rfc3VtX2JveHBsb3QucicpKQoKCnBsdF90cmFpbiA8LSBwbG90X3N1bV9ib3hwbG90ICAgKGRmcmFtZSA9IGRmX2RlY2F0LCBhZXNfbHV0PSBhZXNfbHV0X2RmX2RmX2RlY2F0LCBmYWNldHMgPSBUUlVFICwgcGZhc19ub20gPSBwZmFzX25hbWUgICAgICkgCnByaW50KHBsdF90cmFpbikKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsIkRlY2F0dXJUcmFpblRlc3Rib3hwbG90IixwZmFzX25hbWUsIi5wZGYiKSkscGx0X3RyYWluLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCJEZWNhdHVyVHJhaW5UZXN0Ym94cGxvdCIscGZhc19uYW1lLCIucG5nIikpLHBsdF90cmFpbixkcGk9NjAwKQpgYGAKCiMjIEFsbCBib3hwbG90cwoKQ2hhbmdlZCBncmV5IHN0YXJ0IHRvIDEgaW5zdGVhZCBvZiAwLjgsIGVuZCBhdCAwLjYgaW5zdGVhZCBvZiAwLjQuCkFkZGVkIHNoYXBlcyBhbmQgZmlsbHMgdG8gZGF0YSBwb2ludHMuCgpgYGB7ciBkby1tdWx0aWNoZWNrLWFsbCwgY2FjaGUgPSBUUlVFLCBmaWcud2lkdGg9Ni41LCBmaWcuaGVpZ2h0PTMuNSxkcGk9NjAwfQoKbGV0cyA8LSBMRVRURVJTOwpuYW1lcyhsZXRzKVsxOihsZW5ndGgodW5pcXVlKGRmX2NoZWNrJGRhdGFzZXQpKS00KV08LWFzLmNoYXJhY3Rlcih1bmlxdWUoZGZfY2hlY2skZGF0YXNldCkpWzU6bGVuZ3RoKHVuaXF1ZShkZl9jaGVjayRkYXRhc2V0KSldCgpmb3IgKGQgaW4gdW5pcXVlKGRmX2NoZWNrJGRhdGFzZXQpKSB7ICMgZCA9IHVuaXF1ZShkZl9jaGVjayRkYXRhc2V0KVsxMV0KICAgIGRkc2V0IDwtIGRmX2NoZWNrICU+JSAgICAKICAgIGZpbHRlcihkYXRhc2V0ID09IGQpIAogICAgCiAgICBhZXNfbHV0X2Rkc2V0IDwtIGRkc2V0ICU+JSBzZWxlY3QobGVnZW5kX2xhYmVsLCAgQ2l0eSxUcmFpbl9UZXN0LGRhdGF0eXBlLCBUaW1lLmRlc2MgICkgJT4lIHVuaXF1ZSAoKSAlPiUgaW5uZXJfam9pbihhZXNfbHV0KQogICAgICAKICAgIGd0IDwtIGlmZWxzZShpcy5uYShsZXRzW2RdKSxkLHBhc3RlMChsZXRzW2RdLCI6ICIsIGQpKQogICAgcGx0IDwtIHBsb3Rfc3VtX2JveHBsb3QoZGZyYW1lID0gZGRzZXQsIGFlc19sdXQ9IGFlc19sdXRfZGRzZXQsIGd0aXRsZT0gZ3QsIGZhY2V0cyA9IEZBTFNFLCBwZmFzX25vbSA9IHBmYXNfbmFtZSkKICAgICAKICBwcmludChwbHQpCiAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLAogICAgICAgICAgICAgICAgcGFzdGUwKCBzYSwgZCwiLWJveHBsb3QtIiwgCiAgICAgICAgICAgICAgICBwZmFzX25hbWUsIi5wZGYiKSkgLAogICAgICAgICBwbHQsZHBpPTYwMCkKICAKICAgIGdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIiwKICAgICAgICAgICAgICAgIHBhc3RlMCggc2EsIGQsIi1ib3hwbG90LSIsIAogICAgICAgICAgICAgICAgcGZhc19uYW1lLCIucG5nIikpICwKICAgICAgICAgcGx0LGRwaT02MDApCgp9CgojIyMgbWFrZSBUcmFpbmluZyBwbG90ICAKCmRmX2RfdHJ0IDwtIGRmX2NoZWNrICU+JSAgIAogICAgIGZpbHRlciggKFRyYWluX1Rlc3QgPT0gIlRyYWluIikgJiAoKE91dHB1dF9WYXIgPT0gIk1fQ2JnZF9Dc3MiKSB8IChPdXRwdXRfVmFyID09ICJNX0NzZXJ1bSIpKSkgJT4lCiAgICAgbXV0YXRlX2lmKGlzLmZhY3RvciwgYXMuY2hhcmFjdGVyKSAlPiUgICMgZHJvcCBmYWN0b3IgbGV2ZWxzIHVudXNlZAogICAgIG11dGF0ZShEYXRhc2V0LlRpbWUgPSBmYWN0b3IoRGF0YXNldC5UaW1lKSkgCiAKCiBhZXNfbHV0X2RmX2RfdHJ0IDwtICBkZl9kX3RydCAlPiUgc2VsZWN0KENpdHksIGRhdGF0eXBlLFRpbWUsIFRpbWUuZGVzYywgbGVnZW5kX2xhYmVsKSAlPiUgCiAgIGlubmVyX2pvaW4oYWVzX2x1dCAgKSAlPiUgCiAgIHNlbGVjdCgtVHJhaW5fVGVzdCkgJT4lIHVuZ3JvdXAgKCkgJT4lIHVuaXF1ZSAoKSAgCgpwbHRfdHJhaW4gPC0gICAgcGxvdF9zdW1fYm94cGxvdChkZnJhbWUgPSBkZl9kX3RydCwgYWVzX2x1dD0gYWVzX2x1dF9kZl9kX3RydCwgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3RpdGxlPSJBOiBTdW1tYXJ5IERhdGEgLSBUcmFpbiIgLCBmYWNldHMgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBmYXNfbm9tID0gcGZhc19uYW1lICkKICBwcmludChwbHRfdHJhaW4pCiAgZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLCBwYXN0ZTAoIHNhLCAiU3VtbWFyeVRyYWluRGF0YWJveHBsb3QiLCBwZmFzX25hbWUsIi5wZGYiKSksIHBsdF90cmFpbixkcGk9NjAwKQogIGdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIiwgcGFzdGUwKCBzYSwgIlN1bW1hcnlUcmFpbkRhdGFib3hwbG90IiwgcGZhc19uYW1lLCIucG5nIikpLCBwbHRfdHJhaW4sZHBpPTYwMCkKCgojIyMgIG1ha2UgVGVzdCBwbG90CmRmX2RfdGVzdCA8LSBkZl9jaGVjayAlPiUgICAKICAgIGZpbHRlcigoVHJhaW5fVGVzdCA9PSAiVGVzdCIpICYgCiAgICAgICAgICAgICAoKE91dHB1dF9WYXIgPT0gIk1fQ2JnZF9Dc3MiKSB8IChPdXRwdXRfVmFyID09ICJNX0NzZXJ1bSIpKSkgICU+JQogICAgIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgJT4lICAjIGRyb3AgZmFjdG9yIGxldmVscyB1bnVzZWQKICAgICBtdXRhdGUoRGF0YXNldC5UaW1lID0gZmFjdG9yKERhdGFzZXQuVGltZSkpIAoKYWVzX2x1dF9kZl9kX3Rlc3QgPC0gIGRmX2RfdGVzdCAlPiUgc2VsZWN0KENpdHksIGRhdGF0eXBlLFRpbWUsIFRpbWUuZGVzYywgbGVnZW5kX2xhYmVsKSAlPiUgCiAgIGlubmVyX2pvaW4oYWVzX2x1dCAgKSAlPiUgCiAgIHNlbGVjdCgtVHJhaW5fVGVzdCkgJT4lIHVuZ3JvdXAgKCkgJT4lIHVuaXF1ZSAoKSAgCgpwbHRfdGVzdCA8LSBwbG90X3N1bV9ib3hwbG90KGRmcmFtZSA9IGRmX2RfdGVzdCwgYWVzX2x1dD0gYWVzX2x1dF9kZl9kX3Rlc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGd0aXRsZT0iQjogU3VtbWFyeSBEYXRhIC0gVGVzdCIsIGZhY2V0cyA9IEZBTFNFLCBwZmFzX25vbSA9IHBmYXNfbmFtZSkKICBwcmludChwbHRfdGVzdCkKICBnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlN1bW1hcnlUZXN0RGF0YWJveHBsb3QiLHBmYXNfbmFtZSwiLnBkZiIpKSwgcGx0X3Rlc3QsZHBpPTYwMCkgIAogIGdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiU3VtbWFyeVRlc3REYXRhYm94cGxvdCIscGZhc19uYW1lLCIucG5nIikpLCBwbHRfdGVzdCxkcGk9NjAwKSAgCmBgYAoKIyMgUEZIeFMKIyMjIEJhY2tncm91bmQgcG9zdGVyaW9ycwoKU2hvd3Mgc2hpZnQgaW4gYmFja2dyb3VuZCBlc3RpbWF0ZS4KCmBgYHtyIGdldCBiYWNrZ3JvdW5kLCBjYWNoZSA9IFRSVUUsZmlnLmhlaWdodD02LGZpZy53aWR0aD01LGRwaT02MDB9CgpnbXNjYWxlPC0wLjgKCmRhdCA8LSBtdWx0aWNoZWNrJHBhcm1zLnNhbXBbLGdyZXAoIk1fbG5fQ2JnZCIsbmFtZXMobXVsdGljaGVjayRwYXJtcy5zYW1wKSldCmRhdGFzZXRuYW1lcyA8LSBhcy5jaGFyYWN0ZXIodW5pcXVlKGNhbGliZGF0YSRkYXRhc2V0KSkKZGF0YXNldG5hbWVzIDwtIGdzdWIoIiBUcmFpbiIsIi1UcmFpbiIsZGF0YXNldG5hbWVzKQpkYXRhc2V0bmFtZXMgPC0gZ3N1YigiIFRlc3QiLCItVHJhaW4iLGRhdGFzZXRuYW1lcykKZGF0YXNldG5hbWVzIDwtIGdzdWIoIiBNIiwiIixkYXRhc2V0bmFtZXMpCmRhdGFzZXRuYW1lcyA8LSBnc3ViKCIgRiIsIiIsZGF0YXNldG5hbWVzKQpkYXRhc2V0bmFtZXM8LWRhdGFzZXRuYW1lc1shZHVwbGljYXRlZChkYXRhc2V0bmFtZXMpXQpkYXRhc2V0bmFtZXMgPC0gZGF0YXNldG5hbWVzW2dyZXAoIlRyYWluIixkYXRhc2V0bmFtZXMpXQpuYW1lcyhkYXQpIDwtIGRhdGFzZXRuYW1lcwpkYXQgPC0gZGF0WyxncmVwKCJUcmFpbiIsbmFtZXMoZGF0KSldCmRhdC5kZiA8LSBwaXZvdF9sb25nZXIoZGF0LDE6bmNvbChkYXQpKQpkYXQuZGYgPC0gcmJpbmQoZGF0LmRmLAogICAgICAgICAgICAgICAgZGF0YS5mcmFtZShuYW1lPSJQcmlvciIsdmFsdWU9cm5vcm0oNTAwMCxtPWxvZyhnbXNjYWxlKSxzZD0wLjQwNTUpKSkKZGF0LmRmJG5hbWUgPC0gZmFjdG9yKGRhdC5kZiRuYW1lLGxldmVscz1yZXYoCiAgICAgICAgICAgICAgICAgICAgICAgIGMoIlByaW9yIixkYXRhc2V0bmFtZXNbZ3JlcCgiVHJhaW4iLGRhdGFzZXRuYW1lcyldKSkpCmRhdC5kZiR2YWx1ZSA8LSBleHAoZGF0LmRmJHZhbHVlKQoKcDwtZ2dwbG90KGRhdC5kZikrCiAjIGdlb21fdmlvbGluKGFlcyh4PW5hbWUseT12YWx1ZSxmaWxsPW5hbWU9PSJQcmlvciIpKSsKICBnZW9tX2JveHBsb3QoYWVzKHg9bmFtZSx5PXZhbHVlLGZpbGw9bmFtZT09IlByaW9yIiksb3V0bGllci5zaGFwZT1OQSkrCiAgc2NhbGVfeV9sb2cxMCgpK2Nvb3JkX2ZsaXAoKSsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPU5VTEwsIAogICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKCIjMDA5OTg4IiwgIiNFRTc3MzMiICkpICsKICB0aGVtZV9jbGFzc2ljKCkgKyAgCiAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X2JsYW5rKCkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGdtc2NhbGUsIGNvbG9yPSJkYXJrZ3JleSIsIGxpbmV0eXBlID0gMiwgc2l6ZSA9IDEuMjUpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIixzaXplPTEpKSsKICB5bGFiKCJQb3N0ZXJpb3Igc2hpZnQgaW4gQmFja2dyb3VuZCBDb25jZW50cmF0aW9uIikKCnByaW50KHApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZIeFNfR01fQ2JnZC5wZGYiKSkgLHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRkh4U19HTV9DYmdkLnBuZyIpKSAscCxkcGk9NjAwKQpgYGAKCiMjIyBIYWxmLWxpZmUKCkZvciBQRkh4UywgdGhlIHBvcHVsYXRpb24gR00gb2YgdGhlIGhhbGYtbGlmZSBoYXMgYSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIHRoYXQgaXMgbmFycm93ZXIgdGhhbiB0aGUgcHJpb3IsIHdpdGggYSBwb3N0ZXJpb3IgbWVkaWFuICg5NSUgQ0kpIGVzdGltYXRlIG9mIDMuMDYgKDIuMTYtNC4zNykgeWVhcnMuIFRoZSBwb3B1bGF0aW9uIEdTRCBwb3N0ZXJpb3IgaXMgbGFyZ2VyIHRoYW4gdGhlIHByaW9yIGF0IDEuNDcoMS40NC0xLjc1KS4KCmBgYHtyIHBvc3RlcmlvciBoaXN0b2dyYW1zLCBjYWNoZSA9IFRSVUV9CgoKZGF0IDwtIG11bHRpY2hlY2skcGFybXMuc2FtcFssYygiTV9sbl9rLjEuIiwiVl9sbl9rLjEuIiwgIk1fbG5fVmQuMS4iLCAiU0RfbG5fVmQuMS4iKV0KbmFtZXMoZGF0KSA8LSBjKCJNX2xuX2soMSkiLCJWX2xuX2soMSkiLCAiTV9sbl9WZCgxKSIsICJTRF9sbl9WZCgxKSIpCiAgCnNldC5zZWVkKDMuMTQxNTkpCmRhdCR6X2xuX2sgPC0gcm5vcm0obnJvdyhkYXQpKQpkYXQkel9sbl9WZCA8LSBybm9ybShucm93KGRhdCkpCmRhdCAlPiUgcmVuYW1lXygpCmRhdCRsbl9rX2kgPC0gZGF0JGBNX2xuX2soMSlgICsgc3FydChkYXQkYFZfbG5faygxKWApKmRhdCR6X2xuX2sKZGF0JGxuX1ZkX2kgPC0gZGF0JGBNX2xuX1ZkKDEpYCsgZGF0JGBTRF9sbl9WZCgxKWAqZGF0JHpfbG5fVmQKbGlubW9kIDwtIGxtKGxuX1ZkX2kgfiBsbl9rX2ksZGF0YT1kYXQpCmdncGxvdChkYXQpICsgZ2VvbV9wb2ludChhZXMobG5fa19pLGxuX1ZkX2kpKSArIAogIGxhYnMoc3VidGl0bGU9cGFzdGUoIkFkaiBSMiA9IixzaWduaWYoc3VtbWFyeShsaW5tb2QpJGFkai5yLnNxdWFyZWQsMikpKQpgYGAKCgojIyBDaGVjayBub3JtYWxpdHkKCmBgYHtyIG5vcm1hbGl0eSwgY2FjaGUgPSBUUlVFfQoKcXFub3JtKGRhdCRsbl9rX2ksbWFpbj0ibG4gayBRLVEgTm9ybWFsIikKcXFsaW5lKGRhdCRsbl9rX2ksY29sPSJyZWQiKQpwbG90KGVjZGYoZGF0JGxuX2tfaSkpCnggPC0gc2VxKC0zLDEsMC4wMSkKbV9sbl9rX2kgPC0gICBtZWFuKGRhdCRsbl9rX2kpCnNkX2xuX2tfaSA8LSBzZChkYXQkbG5fa19pKQpsaW5lcyh4LHBub3JtKHgsbWVhbj1tX2xuX2tfaSxzZD1zZF9sbl9rX2kpLGNvbD0icmVkIikKdGV4dChtX2xuX2tfaS0yKnNkX2xuX2tfaSwwLjkscGFzdGUoIm0gPSIsc2lnbmlmKG1fbG5fa19pLDQpLCJcbnNkID0iLHNpZ25pZihzZF9sbl9rX2ksNCkpKQoKcXFub3JtKGRhdCRsbl9WZF9pLG1haW49ImxuIFZkIFEtUSBOb3JtYWwiKQpxcWxpbmUoZGF0JGxuX1ZkX2ksY29sPSJyZWQiKQpwbG90KGVjZGYoZGF0JGxuX1ZkX2kpKQp4IDwtIHNlcSgtMywxLDAuMDEpCm1fbG5fVmRfaSA8LSBtZWFuKGRhdCRsbl9WZF9pKQpzZF9sbl9WZF9pIDwtIHNkKGRhdCRsbl9WZF9pKQoKbGluZXMoeCxwbm9ybSh4LG1lYW49bV9sbl9WZF9pLHNkPXNkX2xuX1ZkX2kpLGNvbD0icmVkIikKdGV4dChtX2xuX1ZkX2ktMipzZF9sbl9WZF9pLDAuOSxwYXN0ZSgibSA9IixzaWduaWYobV9sbl9WZF9pLDQpLCJcbnNkID0iLHNpZ25pZihzZF9sbl9WZF9pLDQpKSkKCmBgYAoKIyMgQ2FsY3VsYXRlIHRhYmxlIHZhbHVlcyBmb3IgaW5kaXZpZHVhbC1sZXZlbApgYGB7ciBtYWtlLWluZGl2aWR1YWwtcGFyYW0tb3V0LCBjYWNoZSA9IFRSVUV9CmhsX2kgPC0gbG9nKDIpLyBleHAoZGF0JGxuX2tfaSkgIyBpbmRpdmlkdWFsIGhhbGYtbGlmZSAKbWVkX2hsX2kgPC0gcGFzdGUoc2lnbmlmIChtZWRpYW4gKGhsX2kpLCAzKSkgIyBtZWRpYW4gb2YgaW5kaXZpZHVhbCBoYWxmLWxpZmUKY2lfbWVkX2hsX2kgPC0gICBwYXN0ZShzaWduaWYgKHF1YW50aWxlKGhsX2ksIHByb2I9YygwLjAyNSwwLjk3NSkpLCAzKSxjb2xsYXBzZT0iLSIpICMgOTVjaSBtZWQgaW5kaXZpZHVhbCBoYWxmbGlmZQpjaTk4X21lZF9obF9pIDwtICAgcGFzdGUoc2lnbmlmIChxdWFudGlsZShobF9pLCBwcm9iPWMoMC4wMSwwLjk5KSksIDMpLGNvbGxhcHNlPSItIikgIyA5OGNpIG1lZCBpbmRpdmlkdWFsIGhhbGZsaWZlCmdtX2hsX2kgPC0gcGFzdGUoc2lnbmlmIChleHAobWVhbihsb2coaGxfaSkpKSwgMykpICMgZ20gKHdoaWNoIHNob3VsZCBiZSByZWFsbHkgY2xvc2UpCmdzZF9obF9pIDwtIHBhc3RlKHNpZ25pZiAoZXhwKHNkKGxvZyhobF9pKSkpLCAzKSkgIyBnc2QgaW5kaXZpZHVhbAoKbWVkX1ZkX2kgPC0gcGFzdGUoc2lnbmlmIChtZWRpYW4oZXhwKGRhdCRsbl9WZF9pKSksIDMpKSAjIG1lZGlhbiBpbmRpdmlkdWFsIFZkCmNpX21lZF9WZF9pIDwtcGFzdGUoc2lnbmlmIChxdWFudGlsZShleHAoZGF0JGxuX1ZkX2kpLCBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksY29sbGFwc2U9Ii0iKSAjIDk1Y2kgbWVkIGluZGl2aWR1YWwgVmQKY2k5OF9tZWRfVmRfaSA8LXBhc3RlKHNpZ25pZiAocXVhbnRpbGUoZXhwKGRhdCRsbl9WZF9pKSwgcHJvYj1jKDAuMDEsMC45OSkpLCAzKSxjb2xsYXBzZT0iLSIpICMgOThjaSBtZWQgaW5kaXZpZHVhbCBWZApnbV92ZF9pIDwtIHBhc3RlKHNpZ25pZiAoZXhwKG1lYW4oZGF0JGxuX1ZkX2kpKSwgMykpICMgZ20gKHdoaWNoIHNob3VsZCBiZSByZWFsbHkgY2xvc2UpCmdzZF92ZF9pPC0gcGFzdGUoc2lnbmlmIChleHAoc2QoZGF0JGxuX1ZkX2kpKSwgMykpICMgZ3NkIGluZGl2CgptZWRfQ0xfaSA8LSBwYXN0ZShzaWduaWYgKG1lZGlhbihleHAoZGF0JGxuX1ZkX2krZGF0JGxuX2tfaSkpLCAzKSkgIyBtZWRpYW4gaW5kaXZpZHVhbCBDTApjaV9tZWRfQ0xfaSA8LXBhc3RlKHNpZ25pZiAocXVhbnRpbGUoZXhwKGRhdCRsbl9WZF9pK2RhdCRsbl9rX2kpLCBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksY29sbGFwc2U9Ii0iKSAjIDk1Y2kgbWVkIGluZGl2aWR1YWwgQ0wKY2k5OF9tZWRfQ0xfaSA8LXBhc3RlKHNpZ25pZiAocXVhbnRpbGUoZXhwKGRhdCRsbl9WZF9pK2RhdCRsbl9rX2kpLCBwcm9iPWMoMC4wMSwwLjk5KSksIDMpLGNvbGxhcHNlPSItIikgIyA5OGNpIG1lZCBpbmRpdmlkdWFsIENMCmdtX0NMX2kgPC0gcGFzdGUoc2lnbmlmIChleHAobWVhbihkYXQkbG5fVmRfaStkYXQkbG5fa19pKSksIDMpKSAjIGdtICh3aGljaCBzaG91bGQgYmUgcmVhbGx5IGNsb3NlKQpnc2RfQ0xfaTwtIHBhc3RlKHNpZ25pZiAoZXhwKHNkKGRhdCRsbl9WZF9pK2RhdCRsbl9rX2kpKSwgMykpICMgZ3NkIGluZGl2CmBgYAoKCmBgYHtyIGhhbGYtbGlmZSxmaWcuaGVpZ2h0PTIuNSxmaWcud2lkdGg9NCxkcGk9NjAwfQpQRkh4U19wcmlvcnMgPC0gZGF0YS5mcmFtZSgKICBoYWxmbGlmZV9HTT0gbG9nKDIpL3Jsbm9ybSg1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFubG9nPS0yLjAzNDIyLHNkbG9nPTAuNDA1NSkpCk1fayA8LSBleHAoYXMubnVtZXJpYyhkYXQkYE1fbG5faygxKWApKQpQRkh4U19oYWxmbGlmZV9HTSA8LSBsb2coMikvTV9rCgpQRkh4U19obGdtX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX3ByaW9ycyRoYWxmbGlmZV9HTSwzKSkKUEZIeFNfaGxnbV9wcl9tZWRfOTVjaSA8LXBhc3RlKHNpZ25pZihxdWFudGlsZShQRkh4U19wcmlvcnMkaGFsZmxpZmVfR00sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZT0iLSIpCgpQRkh4U19obF9tZWRpYW5fZ20gPC0gc2lnbmlmKG1lZGlhbihQRkh4U19oYWxmbGlmZV9HTSksMykKUEZIeFNfaGxfbWVkaWFuX2dtXzk1Y2kgPC0gcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGSHhTX2hhbGZsaWZlX0dNLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoaGFsZmxpZmVfR00sIGNvbG9yID0gIlByaW9yIiksZGF0YT1QRkh4U19wcmlvcnMsZ2VvbT0ibGluZSIsc2l6ZT0yKSsKICBzdGF0X2RlbnNpdHkoYWVzKFBGSHhTX2hhbGZsaWZlX0dNLCBzdGF0KGRlbnNpdHkpLGNvbG9yPSJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSApKwogIHhsaW0oMCwxNSkrCiAgbGFicyh0aXRsZSA9IGJxdW90ZSgiRzogUEZIeFMiflRbMS8yXX4iUG9wdWxhdGlvbiBHTSIpICAsCiAgICAgICBzdWJ0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIE1lZGlhbiAoOTUlIENJKTogIiwKICAgICAgICAgICAgICAgICAgICAgIFBGSHhTX2hsX21lZGlhbl9nbSwiICgiLAogICAgICAgICAgICAgICAgICAgICAgUEZIeFNfaGxfbWVkaWFuX2dtXzk1Y2ksCiAgICAgICAgICAgICAgICAgICAgICAiKSIsc2VwPSIiKSkrCiAgeGxhYihicXVvdGUoIlBvcHVsYXRpb24gR00iflRbMS8yXX4iKHlycykiKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIwogICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKFByaW9yPSIjMDA5OTg4IiwgUG9zdGVyaW9yPSIjRUU3NzMzIiApKSArIAogIHRoZW1lX2NsYXNzaWMoKSArICAKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksbGVnZW5kLnBvc2l0aW9uPWMoMC44LDAuNyksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIixzaXplPTEpLAogICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG9yPU5BKSkKcHJpbnQocCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRkh4U19obF9nbS5wZGYiKSkscCxkcGk9NjAwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwgIlBGSHhTX2hsX2dtLnBuZyIpKSxwLGRwaT02MDApCmBgYAoKCgpgYGB7ciBQRkh4Uy1oYWxmLWxpZmUtZ3NkLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGZpZy5oZWlnaHQ9Mi41LGZpZy53aWR0aD00LGRwaT02MDB9ClBGSHhTX3ByaW9ycyRoYWxmbGlmZV9HU0QgPSAgZXhwKHNxcnQoZXhwKHJub3JtKDUwMDAwLG09bG9nKDAuMiksc2Q9bG9nKDEuMjc1KSkpKSkgClBGSHhTX2hhbGZsaWZlX0dTRCA8LSBleHAoc3FydChkYXQkYFZfbG5faygxKWApKQoKUEZIeFNfaGxnc2RfcHJfbWVkIDwtIHNpZ25pZihtZWRpYW4oUEZIeFNfcHJpb3JzJGhhbGZsaWZlX0dTRCwzKSkKUEZIeFNfaGxnc2RfcHJfbWVkXzk1Y2kgPC1wYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfcHJpb3JzJGhhbGZsaWZlX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPSItIikKUEZIeFNfaGxfZ3NkX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX2hhbGZsaWZlX0dTRCksMykKUEZIeFNfaGxfZ3NkX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRkh4U19oYWxmbGlmZV9HU0QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksMyksY29sbGFwc2U9Ii0iKQpwPC1nZ3Bsb3QoKSsKICBzdGF0X2RlbnNpdHkoYWVzKGhhbGZsaWZlX0dTRCwgY29sb3IgPSAiUHJpb3IiKSxkYXRhPVBGSHhTX3ByaW9ycyxnZW9tPSJsaW5lIiwgc2l6ZT0yKSsKICBzdGF0X2RlbnNpdHkoYWVzKFBGSHhTX2hhbGZsaWZlX0dTRCxzdGF0KGRlbnNpdHkpLCBjb2xvciA9ICJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSkrCiAgeGxpbSgxLDMpKwogIGxhYnModGl0bGUgPSBicXVvdGUoIkg6IFBGSHhTIn5UWzEvMl1+IlBvcHVsYXRpb24gR1NEIiksICAKICAgICAgIHN1YnRpdGxlPXBhc3RlKCJQb3N0ZXJpb3IgTWVkaWFuICg5NSUgQ0kpOiAiLAogICAgICAgICAgICAgICAgICAgICAgUEZIeFNfaGxfZ3NkX21lZCwiICgiLAogICAgICAgICAgICAgICAgICAgICAgUEZIeFNfaGxfZ3NkX21lZF85NWNpLAogICAgICAgICAgICAgICAgICAgICAgIikiLHNlcD0iIikpKwogIHhsYWIoYnF1b3RlKCJQb3B1bGF0aW9uIEdTRCJ+VFsxLzJdKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwjCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICsgCiAgIHRoZW1lX2NsYXNzaWMoKSArICAKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksbGVnZW5kLnBvc2l0aW9uPWMoMC44LDAuNyksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIixzaXplPTEpLAogICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG9yPU5BKSkKcHJpbnQocCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRkh4U19obF9nc2QucGRmIikpICxwLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZIeFNfaGxfZ3NkLnBuZyIpKSAscCxkcGk9NjAwKQpgYGAKCgojIyMgVm9sdW1lIG9mIGRpc3RyaWJ1dGlvbgpGb3IgUEZIeFMsIHRoZSBkYXRhIHdlcmUgbm90IHBhcnRpY3VsYXJseSBpbmZvcm1hdGl2ZSwgYnV0IHNsaWdodGx5IGluY3JlYXNlZCB0aGUgZXN0aW1hdGUgb2YgdGhlIG1lZGlhbiB0byAwLjMwOCgwLjIyMy0wLjU0OCkgc2xpZ2h0bHkgY29tcGFyZWQgdG8gdGhlIGNhc2Ugd2hlcmUgQ2JnZCB3YXMgY29uc2lkZXJlZCB0byBiZSBlbnRpcmVseSBmcm9tIG5vbi1kcmlua2luZyB3YXRlciBzb3VyY2VzLiBUaGV5IHdlcmUgbm90IGluZm9ybWF0aXZlIGFzIHRvIHRoZSBwb3B1bGF0aW9uIEdTRCwgd2l0aCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZXNzZW50aWFsbHkgdW5jaGFuZ2VkIGZyb20gdGhlIHByaW9ycy4KYGBge3IgUEZIeFMtdmQtZ20sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZIeFNfcHJpb3JzJFZkX0dNIDwtIHJsbm9ybSg1MDAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFubG9nPS0xLjM4NjI5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkbG9nPTAuMjYyNCkKUEZIeFNfVmRfR00gPC0gZXhwKGRhdCRgTV9sbl9WZCgxKWApCgogCgpQRkh4U192ZF9nbV9wcl9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRkh4U19wcmlvcnMkVmRfR00sMykpClBGSHhTX3ZkX2dtX3ByX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRkh4U19wcmlvcnMkVmRfR00sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksIDMpLCBjb2xsYXBzZT0iLSIpClBGSHhTX3ZkX2dtX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX1ZkX0dNKSwzKQpQRkh4U192ZF9nbV9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfVmRfR00sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYj1jKDAuMDI1LDAuOTc1KSksMyksY29sbGFwc2U9Ii0iKQoKcDwtZ2dwbG90KCkrCiAgc3RhdF9kZW5zaXR5KGFlcyhWZF9HTSwgY29sb3IgPSAiUHJpb3IiKSxkYXRhPVBGSHhTX3ByaW9ycyxnZW9tPSJsaW5lIixzaXplPTIpKwogIHN0YXRfZGVuc2l0eShhZXMoUEZIeFNfVmRfR00sc3RhdChkZW5zaXR5KSwgY29sb3IgPSAiUG9zdGVyaW9yIiksZ2VvbT0ibGluZSIsc2l6ZT0xLjUpKwogIHhsaW0oMCwxKStsYWJzKHRpdGxlID0gYnF1b3RlKCJHOiBQRkh4UyJ+VltkXX4iUG9wdWxhdGlvbiBHTSIpLAogICAgICAgICAgICAgICAgIHN1YnRpdGxlPXBhc3RlKCJQb3N0ZXJpb3IgTWVkaWFuICg5NSUgQ0kpOiAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBGSHhTX3ZkX2dtX21lZCwiICgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRkh4U192ZF9nbV9tZWRfOTVjaSwiKSIsc2VwPSIiKSkrCiAgIHhsYWIoYnF1b3RlKCJQb3B1bGF0aW9uIEdNIn5WW2RdfiIobC9rZykiKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWU9TlVMTCwjCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICsgIAogIHRoZW1lX2NsYXNzaWMoKSArICAKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksbGVnZW5kLnBvc2l0aW9uPWMoMC44LDAuNyksCiAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIixzaXplPTEpLAogICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJ0cmFuc3BhcmVudCIsIGNvbG9yPU5BKSkKcHJpbnQocCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRkh4U192ZF9nbS5wZGYiKSkgLHAsZHBpPTYwMCkKZ2dzYXZlKGhlcmUgKCJvdXRwdXQtcGxvdHMiLHBhc3RlMCggc2EsICJQRkh4U192ZF9nbS5wbmciKSkgLHAsZHBpPTYwMCkKYGBgCgoKYGBge3IgUEZIeFMtdmQtc2QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZIeFNfcHJpb3JzJFZkX0dTRCA9IGV4cChhYnMocm5vcm0oNTAwMDAsc2Q9MC4xNykpKQpQRkh4U19WZF9HU0QgPC0gZXhwKGRhdCRgU0RfbG5fVmQoMSlgKQoKUEZIeFNfdmRfZ3NkX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX3ByaW9ycyRWZF9HU0QsMykpClBGSHhTX3ZkX2dzZF9wcl9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfcHJpb3JzJFZkX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKClBGSHhTX3ZkX2dzZF9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRkh4U19WZF9HU0QpLDMpClBGSHhTX3ZkX2dzZF9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfVmRfR1NELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoVmRfR1NELCBjb2xvciA9ICJQcmlvciIpLGRhdGE9UEZIeFNfcHJpb3JzLGdlb209ImxpbmUiLHNpemU9MikrCiAgc3RhdF9kZW5zaXR5KGFlcyhQRkh4U19WZF9HU0Qsc3RhdChkZW5zaXR5KSwgY29sb3IgPSAiUG9zdGVyaW9yIiksZ2VvbT0ibGluZSIsc2l6ZT0xLjUpKwogIHhsaW0oMSwzKSsKICBsYWJzKHRpdGxlID0gYnF1b3RlKCJIOiBQRkh4UyJ+VltkXX4iUG9wdWxhdGlvbiBHU0QgIiksCiAgICAgICBzdWJ0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIE1lZGlhbiAoOTUlIENJKTogIiwKICAgICAgICAgICAgICAgICAgICAgIFBGSHhTX3ZkX2dzZF9tZWQsIiAoIiwKICAgICAgICAgICAgICAgICAgICAgIFBGSHhTX3ZkX2dzZF9tZWRfOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICIpIixzZXA9IiIpKSsKICB4bGFiKGJxdW90ZSgiUG9wdWxhdGlvbiBHU0QiflZbZF0pKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT1OVUxMLCAKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoUHJpb3I9IiMwMDk5ODgiLCBQb3N0ZXJpb3I9IiNFRTc3MzMiICkpICsgCiAgdGhlbWVfY2xhc3NpYygpICsgIAogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSxsZWdlbmQucG9zaXRpb249YygwLjgsMC43KSwKICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj0iYmxhY2siLHNpemU9MSksCiAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9InRyYW5zcGFyZW50IiwgY29sb3I9TkEpKQpwcmludChwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwiUEZIeFNfdmRfZ3NkLnBkZiIpKSAscCxkcGk9NjAwKQpnZ3NhdmUoaGVyZSAoIm91dHB1dC1wbG90cyIscGFzdGUwKCBzYSwiUEZIeFNfdmRfZ3NkLnBuZyIpKSAscCxkcGk9NjAwKQoKYGBgCiMjIyBDbGVhcmFuY2UKCkNsIGlzIGsgKiBWZAoKYGBge3IgUEZIeFMtY2wtZ20sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZIeFNfcHJpb3JzJENMX0dNIDwtIFBGSHhTX3ByaW9ycyRWZF9HTSAqIChsb2coMikvUEZIeFNfcHJpb3JzJGhhbGZsaWZlX0dNKQpQRkh4U19DTF9HTSA8LSBleHAoZGF0JGBNX2xuX1ZkKDEpYCArIGRhdCRgTV9sbl9rKDEpYCkKClBGSHhTX2NsX2dtX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX3ByaW9ycyRDTF9HTSwzKSkKUEZIeFNfY2xfZ21fcHJfbWVkXzk1Y2kgPC0gcGFzdGUoc2lnbmlmKHF1YW50aWxlKFBGSHhTX3ByaW9ycyRDTF9HTSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKUEZIeFNfY2xfZ21fbWVkIDwtIHNpZ25pZihtZWRpYW4oUEZIeFNfQ0xfR00pLDMpClBGSHhTX2NsX2dtX21lZF85NWNpIDwtIHBhc3RlKHNpZ25pZihxdWFudGlsZShQRkh4U19DTF9HTSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwzKSxjb2xsYXBzZT0iLSIpCgpwPC1nZ3Bsb3QoKSsKICBzdGF0X2RlbnNpdHkoYWVzKENMX0dNLCBjb2xvciA9ICJQcmlvciIpLGRhdGE9UEZIeFNfcHJpb3JzLGdlb209ImxpbmUiLHNpemU9MikrCiAgc3RhdF9kZW5zaXR5KGFlcyhQRkh4U19DTF9HTSxzdGF0KGRlbnNpdHkpLCBjb2xvciA9ICJQb3N0ZXJpb3IiKSxnZW9tPSJsaW5lIixzaXplPTEuNSkrCiAgeGxpbSgwLDAuMjUpK2xhYnModGl0bGUgPSAiRDogUEZIeFMgQ2xlYXJhbmNlIFBvcC4gR00gIixzdWJ0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIE1lZGlhbiAoOTUlIENJKTogIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRkh4U19jbF9nbV9tZWQsIiAoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQRkh4U19jbF9nbV9tZWRfOTVjaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIsc2VwPSIiKSkrCiAgeGxhYigiUG9wLiBHTSBDTCAobC8oa2cteXIpKSIpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIwogICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKFByaW9yPSIjMDA5OTg4IiwgUG9zdGVyaW9yPSIjRUU3NzMzIiApKSArICAKICB0aGVtZV9jbGFzc2ljKCkgKyAgCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwwLjcpLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsc2l6ZT0xKSwKICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiLCBjb2xvcj1OQSkpCnByaW50KHApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZIeFNfQ0xfZ20ucGRmIikpLCBwLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCAiUEZIeFNfQ0xfZ20ucG5nIikpLCBwLGRwaT02MDApCmBgYAoKYGBge3IgUEZIeFMtQ0wtc2QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZmlnLmhlaWdodD0yLjUsZmlnLndpZHRoPTQsZHBpPTYwMH0KUEZIeFNfcHJpb3JzJENMX0dTRCA9IGV4cChzcXJ0KGxvZyhQRkh4U19wcmlvcnMkVmRfR1NEKV4yICsgCiAgbG9nKFBGSHhTX3ByaW9ycyRoYWxmbGlmZV9HU0QpXjIpKQpQRkh4U19DTF9HU0QgPC0gZXhwKHNxcnQobG9nKFBGSHhTX1ZkX0dTRCleMiArIAogIGxvZyhQRkh4U19oYWxmbGlmZV9HU0QpXjIpKQoKUEZIeFNfQ0xfZ3NkX3ByX21lZCA8LSBzaWduaWYobWVkaWFuKFBGSHhTX3ByaW9ycyRDTF9HU0QsMykpClBGSHhTX0NMX2dzZF9wcl9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfcHJpb3JzJENMX0dTRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9iPWMoMC4wMjUsMC45NzUpKSwgMyksIGNvbGxhcHNlPSItIikKClBGSHhTX0NMX2dzZF9tZWQgPC0gc2lnbmlmKG1lZGlhbihQRkh4U19DTF9HU0QpLDMpClBGSHhTX0NMX2dzZF9tZWRfOTVjaSA8LSBwYXN0ZShzaWduaWYocXVhbnRpbGUoUEZIeFNfQ0xfR1NELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2I9YygwLjAyNSwwLjk3NSkpLDMpLGNvbGxhcHNlPSItIikKCnA8LWdncGxvdCgpKwogIHN0YXRfZGVuc2l0eShhZXMoQ0xfR1NELCBjb2xvciA9ICJQcmlvciIpLGRhdGE9UEZIeFNfcHJpb3JzLGdlb209ImxpbmUiLHNpemU9MikrCiAgc3RhdF9kZW5zaXR5KGFlcyhQRkh4U19DTF9HU0Qsc3RhdChkZW5zaXR5KSwgY29sb3IgPSAiUG9zdGVyaW9yIiksZ2VvbT0ibGluZSIsc2l6ZT0xLjUpKwogIHhsaW0oMSwzKSsKICBsYWJzKHRpdGxlID0gYnF1b3RlKCJIOiBQRkh4UyJ+Q0x+IlBvcHVsYXRpb24gR1NEICIpLAogICAgICAgc3VidGl0bGU9cGFzdGUoIlBvc3RlcmlvciBNZWRpYW4gKDk1JSBDSSk6ICIsCiAgICAgICAgICAgICAgICAgICAgICBQRkh4U19DTF9nc2RfbWVkLCIgKCIsCiAgICAgICAgICAgICAgICAgICAgICBQRkh4U19DTF9nc2RfbWVkXzk1Y2ksCiAgICAgICAgICAgICAgICAgICAgICAiKSIsc2VwPSIiKSkrCiAgeGxhYihicXVvdGUoIlBvcHVsYXRpb24gR1NEIn5DTCkpKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPU5VTEwsIAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YyhQcmlvcj0iIzAwOTk4OCIsIFBvc3Rlcmlvcj0iI0VFNzczMyIgKSkgKyAKICB0aGVtZV9jbGFzc2ljKCkgKyAgCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLGxlZ2VuZC5wb3NpdGlvbj1jKDAuOCwwLjcpLAogICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yPSJibGFjayIsc2l6ZT0xKSwKICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0idHJhbnNwYXJlbnQiLCBjb2xvcj1OQSkpCnByaW50KHApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCJQRkh4U19DTF9nc2QucGRmIikpICxwLGRwaT02MDApCmdnc2F2ZShoZXJlICgib3V0cHV0LXBsb3RzIixwYXN0ZTAoIHNhLCJQRkh4U19DTF9nc2QucG5nIikpICxwLGRwaT02MDApCmBgYAojIyBUYWJsZSBzaWduaWZpY2FudCBkaWdpdCB2YWx1ZXMKCmBgYHtyIHRhYmxlLXZhcnMgfQpQRkh4U19obGdtX3ByX21lZCA8LSBwYXN0ZShzaWduaWYoUEZIeFNfaGxnbV9wcl9tZWQsIDMpKQpQRkh4U19obF9tZWRpYW5fZ208LSBwYXN0ZShzaWduaWYoUEZIeFNfaGxfbWVkaWFuX2dtLCAzKSkKUEZIeFNfaGxnc2RfcHJfbWVkPC0gcGFzdGUoc2lnbmlmKFBGSHhTX2hsZ3NkX3ByX21lZCwgMykpClBGSHhTX2hsX2dzZF9tZWQ8LSBwYXN0ZShzaWduaWYoUEZIeFNfaGxfZ3NkX21lZCwgMykpClBGSHhTX3ZkX2dtX3ByX21lZDwtIHBhc3RlKHNpZ25pZihQRkh4U192ZF9nbV9wcl9tZWQsIDMpKQpQRkh4U192ZF9nbV9tZWQ8LSBwYXN0ZShzaWduaWYoUEZIeFNfdmRfZ21fbWVkLCAzKSkKUEZIeFNfdmRfZ3NkX3ByX21lZDwtIHBhc3RlKHNpZ25pZihQRkh4U192ZF9nc2RfcHJfbWVkLCAzKSkKUEZIeFNfdmRfZ3NkX21lZDwtIHBhc3RlKHNpZ25pZihQRkh4U192ZF9nc2RfbWVkLCAzKSkKUEZIeFNfY2xfZ21fcHJfbWVkPC0gcGFzdGUoc2lnbmlmKFBGSHhTX2NsX2dtX3ByX21lZCwgMykpClBGSHhTX2NsX2dtX21lZDwtIHBhc3RlKHNpZ25pZihQRkh4U19jbF9nbV9tZWQsIDMpKQpgYGAKCiMjIyBQb3B1bGF0aW9uIG1lZGlhbiBlc3RpbWF0ZXMgWzk1JSBDSV0gCgp8IFBhcmFtZXRlciAgICAgICAgICAgICAgICAgICAgICB8IFByaW9yIEdNICAgICAgfCBQb3N0ZXJpb3IgR00gfCBQcmlvciAgR1NEICAgIHwgUG9zdGVyaW9yIEdTRCB8IAp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLTp8IAp8IEhhbGYtbGlmZSAoeWVhcnMpICB8IGByIHBhc3RlKFBGSHhTX2hsZ21fcHJfbWVkKSBgIHwgICBgciBwYXN0ZShQRkh4U19obF9tZWRpYW5fZ20pIGAgICAgfCBgciAgcGFzdGUoUEZIeFNfaGxnc2RfcHJfbWVkKSBgICAgICAgICAgICB8IGByIHBhc3RlKFBGSHhTX2hsX2dzZF9tZWQpYCAgfCAKfCBITCAgWzk1JSBDSV0gIHxgciBwYXN0ZTAoIlsiLFBGSHhTX2hsZ21fcHJfbWVkXzk1Y2ksIl0iKWAgfCBgciBwYXN0ZTAoICJbIixQRkh4U19obF9tZWRpYW5fZ21fOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCJbIixQRkh4U19obGdzZF9wcl9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCAiWyIsUEZIeFNfaGxfZ3NkX21lZF85NWNpLCAiXSIpYHwKfCBWb2x1bWUgb2YgZGlzdHJpYnV0aW9uICAgIHwgYHIgcGFzdGUoUEZIeFNfdmRfZ21fcHJfbWVkKSBgIHwgICAgYHIgcGFzdGUoICBQRkh4U192ZF9nbV9tZWQpIGB8ICAgYHIgIHBhc3RlKFBGSHhTX3ZkX2dzZF9wcl9tZWQpYCAgfGByICBwYXN0ZShQRkh4U192ZF9nc2RfbWVkKWAgfCAgCnwgJFZfRCQgWzk1JSBDSV0gICAgfGByIHBhc3RlMCggIlsiLFBGSHhTX3ZkX2dtX3ByX21lZF85NWNpLCJdIilgfCBgciBwYXN0ZTAoICJbIixQRkh4U192ZF9nbV9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCJbIixQRkh4U192ZF9nc2RfcHJfbWVkXzk1Y2ksICJdIilgfCBgciBwYXN0ZTAoICAiWyIsUEZIeFNfdmRfZ3NkX21lZF85NWNpLCAiXSIpYHwgCnwgQ2xlYXJhbmNlICAgIHwgYHIgcGFzdGUoUEZIeFNfY2xfZ21fcHJfbWVkKSBgIHwgICAgYHIgcGFzdGUoICBQRkh4U19jbF9nbV9tZWQpIGB8ICAgYHIgIHBhc3RlKClgICB8YHIgIHBhc3RlKClgIHwgIAp8ICRDTCQgWzk1JSBDSV0gICAgfGByIHBhc3RlMCggIlsiLFBGSHhTX2NsX2dtX3ByX21lZF85NWNpLCJdIilgfCBgciBwYXN0ZTAoICJbIixQRkh4U19jbF9nbV9tZWRfOTVjaSwiXSIpYHwgYHIgcGFzdGUwKCJbIiwgIl0iKWB8IGByIHBhc3RlMCggICJbIiwgIl0iKWB8IAogCgoKIyMjIEluZGl2aWR1YWwgUG9zdGVyaW9yIGVzdGltYXRlcyAKCnwgUGFyYW1ldGVyICAgICAgICAgICAgICAgICAgICAgIHwgIG1lZGlhbiBHTSAgWzk1JSBDSV0gW1s5OCUgQ0ldXSB8IEdNIGNhbGN1bGF0b3IgaW5wdXQgIHwgIEdTRCBpbmRpdmlkdWFsIHwKfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tOnwgCnwgSGFsZi1saWZlICh5ZWFycykgICAgICAgICAgICAgIHwgYHIgIHBhc3RlKG1lZF9obF9pLCAiWyIsY2lfbWVkX2hsX2ksIl0iLCAiW1siLGNpOThfbWVkX2hsX2ksIl1dIikgYCB8IGByICBwYXN0ZShnbV9obF9pKSBgIHwgYHIgIHBhc3RlKGdzZF9obF9pKSBgfAp8IFZvbHVtZSBvZiBkaXN0cmlidXRpb24gJFZfRCQgICB8IGByICBwYXN0ZShtZWRfVmRfaSwgIlsiLGNpX21lZF9WZF9pLCJdIiwgIltbIixjaTk4X21lZF9WZF9pLCJdXSIpIGAgfCBgciAgcGFzdGUoZ21fdmRfaSkgYCB8IGByICBwYXN0ZShnc2RfdmRfaSkgYHwgCnwgQ2xlYXJhbmNlIChML2tnLXlyKSAgIHwgYHIgIHBhc3RlKG1lZF9DTF9pLCAiWyIsY2lfbWVkX0NMX2ksIl0iLCAiW1siLGNpOThfbWVkX0NMX2ksIl1dIikgYCB8IGByICBwYXN0ZShnbV9DTF9pKSBgIHwgYHIgIHBhc3RlKGdzZF9DTF9pKSBgfCAKCgoKIyMjIFNlc3Npb24gaW5mb3JtYXRpb24KYGBge3IgZWNobz1GQUxTRX0KZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYA==